/* Trit home page. Storyboard, timing and capture sources: Website/home/README.md section 02.

   Behaviour layers:
   1. Base styles are the composed final frame of every scene: what visitors see with
      prefers-reduced-motion, without JavaScript, and when no scroll timeline is available.
   2. html.intro-on (inline head script, motion allowed) fades the intact logo in on load.
   3. html.film runs the scroll film: tall scenes with sticky stages, and every [data-k] element
      scrubs its keyframes between --from and --to, in percent of its scene's view timeline.
      Native: CSS scroll-driven animations. Fallback (html.film-fallback, set by home.js): the same
      keyframes, paused, scrubbed through animation-delay by --p (0 to 100) per scene.
   Every beat of a scene reads one timeline, so a later beat can never start before an earlier one
   ends, at any viewport size or scroll speed. Only transform and opacity animate.
   The app captures are real simulator screenshots; motion moves, crossfades and wipes them, and the
   spotlight and wipe shadow are overlays on the device frame: no capture pixel is ever altered.
   The three film scenes (#review, #fix, #undo) and their beats are generated by Tools/build-film.py
   from Tools/film-story.json between the @gen markers. */

@property --from { syntax: "<number>"; inherits: false; initial-value: 0; }
@property --to { syntax: "<number>"; inherits: false; initial-value: 100; }
@property --i { syntax: "<number>"; inherits: false; initial-value: 0; }
@property --p { syntax: "<number>"; inherits: true; initial-value: 0; }

.home-page { --vignette: rgba(39, 71, 214, .14); --mark-glow: rgba(47, 108, 255, .38); overflow-x: clip; }
.site-header--overlay { position: absolute; inset: 0 0 auto; }

/* ---------------------------------------------------------------- stage */
.scene__stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: clamp(24px, 5vw, 80px);
  min-height: 100svh;
  padding: clamp(72px, 10vh, 112px) var(--gutter);
  overflow: clip;
  background: radial-gradient(42% 40% at 50% 52%, var(--vignette), transparent 70%);
}
.scene__title, .statement {
  margin: 0;
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.05;
  text-wrap: balance;
}
.scene__title { position: relative; z-index: 2; max-width: 11em; font-size: clamp(2rem, 3.6vw, 3.4rem); }
.scene__visual { position: relative; z-index: 1; display: flex; justify-content: center; grid-column: 2; grid-row: 1; }

/* Review and Undo: title on the left of the centred device. Fix: title on the right. */
.scene--review .scene__title, .scene--undo .scene__title { grid-column: 1; grid-row: 1; }
.scene--fix .scene__title { grid-column: 3; grid-row: 1; }

/* ---------------------------------------------------------------- hero */
.hero__stage { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); padding-top: 88px; }
.hero__copy { position: relative; z-index: 2; }
/* Two set lines: each fits its column at these sizes (about 9.6em for "Nothing in between."). */
.hero h1 { margin: 0 0 32px; font-size: clamp(2.4rem, 4vw, 4rem); font-weight: 750; letter-spacing: -.045em; line-height: 1.02; }
.hero__line { display: block; white-space: nowrap; }
.hero__line--quiet { color: var(--text-secondary); }
.mark { position: relative; justify-self: center; width: min(42vw, 64svh, 620px); aspect-ratio: 1; }
.mark__glow { position: absolute; inset: -24%; background: radial-gradient(closest-side, var(--mark-glow), transparent 72%); pointer-events: none; }
.mark__logo { position: relative; width: 100%; height: 100%; }

/* ---------------------------------------------------------------- device: real captures */
/* A device frame holds a scene's captures as stacked shots. Every capture is a real simulator screenshot
   with its status and navigation bars cropped; --h is the tallest crop of the scene in points (390 pt wide, iPhone 13),
   so the frame's aspect is 390 / --h. A shorter crop sits at the bottom on its own top-row colour
   (--bg, sampled from the capture), never stretched. Without the film only the shot marked
   .shot--final shows; the others stay display: none, so their lazy images are never requested.
   Per-scene and per-shot values (--h, --bg, spotlight bands) are CSS rules in the generated frames block
   below, not style attributes, so the Content-Security-Policy needs no inline-style allowance. */
.device {
  --h: 737;
  --device-w: min(340px, calc((100svh - 190px) * 390 / var(--h)));
  position: relative;
  width: var(--device-w);
  aspect-ratio: 390 / var(--h);
  margin: 0;
  overflow: hidden;
  border-radius: 5.5% 5.5% 14% 14% / 2.9% 2.9% 7.5% 7.5%;
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--separator), var(--shadow);
}
.shot { position: absolute; inset: 0; display: block; background: var(--bg, var(--canvas)); }
.shot img { display: block; width: 100%; height: 100%; object-fit: contain; object-position: 50% 100%; }
.shot:not(.shot--final), .spot { display: none; }
/* Spotlight: dims everything outside one horizontal band (--y0 to --y1, % of the frame height). An overlay
   on the frame; it never paints into the capture. Hidden at rest. */
.spot {
  --spot: rgba(4, 7, 14, .58);
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to bottom, var(--spot) calc(var(--y0) - 3%), transparent var(--y0),
    transparent var(--y1), var(--spot) calc(var(--y1) + 3%));
}
/* Wipe: an overflow window slides down while its content slides up by the same amount, so the capture
   inside stays put and is revealed top to bottom (transform only). */
.wipe { position: absolute; inset: 0; overflow: hidden; box-shadow: 0 14px 28px rgba(2, 6, 18, .28); }
.camera { position: relative; }
/* Scene frames: device height, shot backgrounds and spotlight bands (generated from Tools/film-story.json). */
/* @gen:frames:start */
.scene--review .device { --h: 744; }
.shot--review-diff { --bg: #0A0D11; }
.shot--review-confirm { --bg: #0D0D0F; }
.shot--review-posted { --bg: #19191C; }
.scene--review .spot--1 { --y0: 49.5%; --y1: 54.4%; }
.scene--review .spot--2 { --y0: 37.5%; --y1: 53.5%; }
.scene--fix .device { --h: 740; }
.shot--fix-select { --bg: #0A0D11; }
.shot--fix-commit { --bg: #0E1116; }
.shot--fix-sync { --bg: #0B0E11; }
.scene--fix .spot--1 { --y0: 40%; --y1: 65.5%; }
.scene--fix .spot--2 { --y0: 77%; --y1: 93%; }
.scene--undo .device { --h: 744; }
.shot--undo-before { --bg: #161A21; }
.shot--undo-confirm { --bg: #07090B; }
.shot--undo-after { --bg: #161A21; }
.scene--undo .spot--1 { --y0: 0%; --y1: 9.8%; }
.scene--undo .spot--2 { --y0: 0%; --y1: 9.8%; }
/* @gen:frames:end */

/* ---------------------------------------------------------------- private */
.private { grid-template-columns: minmax(0, 1fr); align-content: center; justify-items: start; gap: clamp(40px, 7vh, 72px); max-width: 1180px; margin: 0 auto; background: none; }
.statement { max-width: 15ch; font-size: clamp(2.4rem, 5.4vw, 5rem); }
.statement span { display: inline-block; }
.facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 clamp(20px, 3vw, 40px); width: 100%; margin: 0; padding: 0; list-style: none; }
.facts li { padding-top: 16px; border-top: 1px solid var(--separator); color: var(--text-secondary); font-size: clamp(17px, 1.4vw, 19px); line-height: 1.4; }
/* Reading order of the statement words and the facts (--i), as rules rather than style attributes. */
.statement span:nth-child(2) { --i: 1; }
.statement span:nth-child(3) { --i: 2; }
.statement span:nth-child(4) { --i: 3; }
.statement span:nth-child(5) { --i: 4; }
.statement span:nth-child(6) { --i: 5; }
.statement span:nth-child(7) { --i: 6; }
.statement span:nth-child(8) { --i: 7; }
.statement span:nth-child(9) { --i: 8; }
.statement span:nth-child(10) { --i: 9; }
.facts li:nth-child(2) { --i: 1; }
.facts li:nth-child(3) { --i: 2; }

/* ---------------------------------------------------------------- end card */
/* One horizontal closing lockup: the app icon on the left; on the right "Trit" over the disabled badge.
   Two items hang to the right of that column without taking part in layout, so the centred group is
   exactly icon + gap + max(name, badge): "Coming soon" sits on the name's baseline as a zero-width
   flex item.
   The section fills the last viewport above the footer, so at the page end the lockup is centred
   between the viewport top and the footer's top edge.
   --footer-h mirrors .site-footer in site.css (px font size, so it does not scale with text):
   desktop 16 + 44 + 16 padding/target + 1 border; phones (max-width 760px, column) 12 + 13 * 1.55
   + 4 + 44 + 16 + 1, plus the bottom safe area on both.
   The icon spans the name and the badge: the name's line box is set to about its cap height
   (line-height .72), so the icon's top meets the top of "Trit" and its bottom meets the badge's
   bottom. --hang is how far "Coming soon" reaches past the badge; the group is centred, so the same
   room is kept on the left, and the icon shrinks (--mark-room) before "Coming soon" would enter the
   gutter. */
.endcard {
  --footer-h: calc(77px + env(safe-area-inset-bottom, 0px));
  --badge-h: 48px;
  --name-size: clamp(44px, 4.4vw, 60px);
  --name-gap: clamp(14px, 1.4vw, 18px);
  --lockup-gap: clamp(18px, 2.2vw, 28px);
  --status-gap: 14px;
  --hang: 48px; /* "Coming soon" past the badge: 82 + 14 + 92 - 144 = 45px at 1440px, rounded up */
  --mark-room: calc(100vw - 2 * (var(--gutter) + var(--hang)) - var(--lockup-gap) - 3 * var(--badge-h));
  display: grid;
  place-content: center;
  min-height: calc(100vh - var(--footer-h));
  min-height: calc(100svh - var(--footer-h));
  padding: 40px var(--gutter);
  background: radial-gradient(44% 38% at 50% 46%, var(--vignette), transparent 70%);
}
.lockup {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-areas: "mark name" "mark store";
  column-gap: var(--lockup-gap);
  align-items: start;
  justify-items: start;
}
.lockup__mark {
  grid-area: mark;
  --mark: calc(var(--name-size) * .72 + var(--name-gap) + var(--badge-h));
  width: min(var(--mark), var(--mark-room));
  height: auto;
}
.lockup__title { grid-area: name; display: flex; align-items: baseline; margin-bottom: var(--name-gap); }
.lockup__name {
  margin: 0;
  font-size: var(--name-size);
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: .72;
}
/* Zero-width item on the name's baseline: it never widens the column, and the negative block margins
   keep its descent from growing the row (the name's cap-height box stays the row height). */
.lockup .lockup__status { position: relative; left: var(--status-gap); flex: none; width: 0; margin-block: -1em; line-height: 1; }
.lockup__store { grid-area: store; }
/* The badge is disabled (never a target), so it needs no padded hit area here. */
.lockup .store__badge { margin: 0; padding: 0; }
.lockup .store__badge img { height: var(--badge-h); }
@media (max-width: 760px) {
  .endcard { --footer-h: calc(97.15px + env(safe-area-inset-bottom, 0px)); }
}

/* ---------------------------------------------------------------- phones (portrait) */
@media (max-width: 899px) and (orientation: portrait), (max-width: 599px) {
  .scene__stage { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); align-content: start; justify-items: center; gap: 24px; padding: 76px 16px 28px; }
  .scene__visual { grid-column: 1; grid-row: 2; }
  .scene__title, .scene--review .scene__title, .scene--undo .scene__title, .scene--fix .scene__title { grid-column: 1; grid-row: 1; max-width: 14em; font-size: clamp(1.9rem, 8.4vw, 2.5rem); text-align: center; }
  .device { --device-w: min(78vw, calc((100svh - 210px) * 390 / var(--h))); }
  .hero__stage { grid-template-columns: 1fr; grid-template-rows: auto auto; align-content: center; justify-items: start; gap: 28px; padding: 76px 16px 40px; }
  .hero .mark { order: -1; justify-self: center; width: min(76vw, 42svh); }
  /* Stacked under the centred logo, the copy block (as wide as its longest line) is centred on the
     page while its lines and the badge row stay left-aligned with each other. */
  .hero__copy { justify-self: center; }
  .hero h1 { margin-bottom: 24px; font-size: clamp(1.9rem, 9.2vw, 3.2rem); }
  .store__badge img { height: 44px; }
  .endcard { --badge-h: 44px; --name-size: clamp(40px, 11vw, 48px); --lockup-gap: 16px; --status-gap: 12px; --hang: 30px; } /* "Coming soon" 30px past the badge with the 40px name (up to 364px wide); wider phones never reach --mark-room */
  .private { justify-items: start; gap: 36px; padding: 72px 20px 40px; }
  .statement { font-size: clamp(2.1rem, 10vw, 3rem); }
  .facts { grid-template-columns: 1fr; }
  .facts li { padding: 14px 0; }
  .private { grid-template-rows: auto auto; align-content: center; }
}
@media (orientation: landscape) and (max-height: 560px) {
  .scene__stage { padding-block: 56px 16px; }
  .device { --device-w: calc((100svh - 80px) * 390 / var(--h)); }
  .mark { width: min(36vw, 62svh); }
}

/* ================================================================= motion */
@media (prefers-reduced-motion: no-preference) {
  /* Load: the intact logo fades in. Copy is visible immediately (it is the LCP candidate). */
  .intro-on .mark__logo { animation: logo-in .7s cubic-bezier(.33, 1, .68, 1) both; }

  /* Film layout: pinned scenes and their scroll lengths. */
  .film .hero { --len: 170vh; }
  .film .scene--private { --len: 230vh; }
  .film :is(.hero, .scene--film, .scene--private) { height: var(--len); }
  .film :is(.hero, .scene--film, .scene--private) > .scene__stage { position: sticky; top: 0; height: 100svh; min-height: 0; }
  .film [data-range="contain"] { --rn: contain; }

  /* Scrub contract for every [data-k] element. */
  .film [data-k] {
    animation-duration: 1ms;
    animation-duration: auto;
    animation-fill-mode: both;
    animation-timing-function: linear;
    animation-range: var(--rn, cover) calc(var(--from) * 1%) var(--rn, cover) calc(var(--to) * 1%);
  }
  .film #top { view-timeline: --s-top block; }
  .film #review { view-timeline: --s-review block; }
  .film #fix { view-timeline: --s-fix block; }
  .film #undo { view-timeline: --s-undo block; }
  .film #private { view-timeline: --s-private block; }
  .film #coming { view-timeline: --s-coming block; }
  .film #top [data-k] { animation-timeline: --s-top; }
  .film #review [data-k] { animation-timeline: --s-review; }
  .film #fix [data-k] { animation-timeline: --s-fix; }
  .film #undo [data-k] { animation-timeline: --s-undo; }
  .film #private [data-k] { animation-timeline: --s-private; }
  .film #coming [data-k] { animation-timeline: --s-coming; }
  .film-fallback [data-k] {
    animation-duration: 1s;
    animation-play-state: paused;
    animation-delay: calc(clamp(0, (var(--p) - var(--from)) / max(.001, var(--to) - var(--from)), 1) * -1s);
  }

  /* 01 Title (contain range: the 70vh while the stage is pinned). */
  .film .hero__copy { --from: 0; --to: 45; animation-name: fade-out-up; }
  .film .mark { --from: 0; --to: 70; animation-name: logo-out; }

  /* Film scenes: every shot and spotlight takes part; beats come from the generated block below. */
  .film .scene--film :is(.shot, .spot) { display: block; }
  /* @gen:motion:start */
  /* 02 Review (cover, 480vh: entry 0-17.24, pinned 17.24-82.76, exit 82.76-100).
     close-up on new lines 8-9 0-34 (spotlight 14-36) | to the comment + Post sheet 34-42, hold 42-52 | to the posted thread 52-60, hold 60-66 (spotlight 60-72) | pull back 66-76 | title 72-80 */
  .film .scene--review { --len: 480vh; }
  .film .scene--review .camera { --from: 0; --to: 76; animation-name: review-camera; }
  @media (max-width: 899px) and (orientation: portrait), (max-width: 599px) { .film .scene--review .camera { animation-name: review-camera-compact; } }
  .film .scene--review .shot:nth-of-type(2) { --from: 36; --to: 42; animation-name: shot-in; }
  .film .scene--review .shot:nth-of-type(3) { --from: 54; --to: 60; animation-name: shot-in; }
  .film .scene--review .spot--1 { --from: 14; --to: 36; animation-name: review-spot-1; }
  .film .scene--review .spot--2 { --from: 60; --to: 72; animation-name: review-spot-2; }
  .film .scene--review .scene__title { --from: 72; --to: 80; animation-name: rise-in; }

  /* 03 Fix (cover, 560vh: entry 0-15.15, pinned 15.15-84.85, exit 84.85-100).
     selected lines 0-34 (spotlight 12-34) | commit message 34-40, hold 40-50 | Sync sheet 52-58, hold 58-66 (spotlight 58-70) | pull back 66-76 | title 72-80 */
  .film .scene--fix { --len: 560vh; }
  .film .scene--fix .camera { --from: 0; --to: 76; animation-name: fix-camera; }
  @media (max-width: 899px) and (orientation: portrait), (max-width: 599px) { .film .scene--fix .camera { animation-name: fix-camera-compact; } }
  .film .scene--fix .shot:nth-of-type(2) { --from: 34; --to: 40; animation-name: shot-in; }
  .film .scene--fix .shot:nth-of-type(3) { --from: 52; --to: 58; animation-name: shot-in; }
  .film .scene--fix .spot--1 { --from: 12; --to: 34; animation-name: fix-spot-1; }
  .film .scene--fix .spot--2 { --from: 58; --to: 70; animation-name: fix-spot-2; }
  .film .scene--fix .scene__title { --from: 72; --to: 80; animation-name: rise-in; }

  /* 04 Undo (cover, 480vh: entry 0-17.24, pinned 17.24-82.76, exit 82.76-100).
     close-up on HEAD 0-30 (spotlight 12-30) | to the Undo sheet 30-38, hold 38-48 | pull back 48-56 | wipe to the after state 58-68 | new HEAD spotlight 68-80 | title 70-78 */
  .film .scene--undo { --len: 480vh; }
  .film .scene--undo .camera { --from: 0; --to: 56; animation-name: undo-camera; }
  @media (max-width: 899px) and (orientation: portrait), (max-width: 599px) { .film .scene--undo .camera { animation-name: undo-camera-compact; } }
  .film .scene--undo .shot:nth-of-type(2) { --from: 32; --to: 38; animation-name: shot-in; }
  .film .scene--undo .wipe { --from: 58; --to: 68; animation-name: wipe-window; }
  .film .scene--undo .wipe__content { --from: 58; --to: 68; animation-name: wipe-content; }
  .film .scene--undo .spot--1 { --from: 12; --to: 30; animation-name: undo-spot-1; }
  .film .scene--undo .spot--2 { --from: 68; --to: 80; animation-name: undo-spot-2; }
  .film .scene--undo .scene__title { --from: 70; --to: 78; animation-name: rise-in; }
  /* @gen:motion:end */

  /* 05 Private (cover, 230vh: entry 0-30.3, pinned 30.3-69.7). Words read in, then the facts. */
  .film .statement span { --from: calc(26 + var(--i) * 2.4); --to: calc(32 + var(--i) * 2.4); animation-name: word-in; }
  .film .facts li { --from: calc(52 + var(--i) * 3); --to: calc(60 + var(--i) * 3); animation-name: rise-in; }

  /* 06 End card (normal flow; every beat ends before the page end can stop the timeline). */
  .film .lockup__mark { --from: 6; --to: 30; animation-name: rise-in; }
  .film .lockup__title { --from: 12; --to: 32; animation-name: rise-in; }
  .film .lockup__store { --from: 16; --to: 34; animation-name: rise-in; }
}

/* ---------------------------------------------------------------- keyframes */
@keyframes logo-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes logo-out { 0% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.5, 0, .75, 0); } 100% { opacity: 0; transform: scale(.96); } }
@keyframes fade-out-up { 0% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.5, 0, .75, 0); } 100% { opacity: 0; transform: translateY(-6vh); } }
@keyframes rise-in { 0% { opacity: 0; transform: translateY(24px); animation-timing-function: cubic-bezier(.16, 1, .3, 1); } 100% { opacity: 1; transform: none; } }
@keyframes word-in { from { opacity: .16; } to { opacity: 1; } }
/* @gen:keyframes:start */
@keyframes shot-in { 0% { opacity: 0; animation-timing-function: cubic-bezier(.33, 0, .67, 1); } 100% { opacity: 1; } }
@keyframes wipe-window { 0% { transform: translateY(-100%); animation-timing-function: cubic-bezier(.45, 0, .55, 1); } 100% { transform: none; } }
@keyframes wipe-content { 0% { transform: translateY(100%); animation-timing-function: cubic-bezier(.45, 0, .55, 1); } 100% { transform: none; } }
@keyframes review-camera {
  0% { transform: translate(0%, -6%) scale(2); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  44.74% { transform: translate(0%, -6%) scale(2); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  55.26% { transform: translate(0%, -25.5%) scale(1.5); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  68.42% { transform: translate(0%, -25.5%) scale(1.5); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  78.95% { transform: translate(0%, 7.2%) scale(1.8); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  86.84% { transform: translate(0%, 7.2%) scale(1.8); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes review-camera-compact {
  0% { transform: translate(0%, -3.84%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  44.74% { transform: translate(0%, -3.84%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  55.26% { transform: translate(0%, -21.76%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  68.42% { transform: translate(0%, -21.76%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  78.95% { transform: translate(0%, 5.12%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  86.84% { transform: translate(0%, 5.12%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes review-spot-1 { 0% { opacity: 0; } 27.27% { opacity: 1; } 81.82% { opacity: 1; } 100% { opacity: 0; } }
@keyframes review-spot-2 { 0% { opacity: 0; } 25% { opacity: 1; } 66.67% { opacity: 1; } 100% { opacity: 0; } }
@keyframes fix-camera {
  0% { transform: translate(0%, -3.8%) scale(1.9); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  44.74% { transform: translate(0%, -3.8%) scale(1.9); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  52.63% { transform: translate(0%, 41.4%) scale(1.8); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  65.79% { transform: translate(0%, 41.4%) scale(1.8); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  76.32% { transform: translate(0%, -37.4%) scale(1.7); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  86.84% { transform: translate(0%, -37.4%) scale(1.7); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes fix-camera-compact {
  0% { transform: translate(0%, -2.56%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  44.74% { transform: translate(0%, -2.56%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  52.63% { transform: translate(0%, 29.44%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  65.79% { transform: translate(0%, 29.44%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  76.32% { transform: translate(0%, -28.16%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  86.84% { transform: translate(0%, -28.16%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes fix-spot-1 { 0% { opacity: 0; } 27.27% { opacity: 1; } 81.82% { opacity: 1; } 100% { opacity: 0; } }
@keyframes fix-spot-2 { 0% { opacity: 0; } 25% { opacity: 1; } 66.67% { opacity: 1; } 100% { opacity: 0; } }
@keyframes undo-camera {
  0% { transform: translate(0%, 47.6%) scale(1.7); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  53.57% { transform: translate(0%, 47.6%) scale(1.7); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  67.86% { transform: translate(0%, -33%) scale(1.5); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  85.71% { transform: translate(0%, -33%) scale(1.5); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes undo-camera-compact {
  0% { transform: translate(0%, 35.84%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  53.57% { transform: translate(0%, 35.84%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  67.86% { transform: translate(0%, -28.16%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  85.71% { transform: translate(0%, -28.16%) scale(1.28); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  100% { transform: none; }
}
@keyframes undo-spot-1 { 0% { opacity: 0; } 33.33% { opacity: 1; } 77.78% { opacity: 1; } 100% { opacity: 0; } }
@keyframes undo-spot-2 { 0% { opacity: 0; } 25% { opacity: 1; } 66.67% { opacity: 1; } 100% { opacity: 0; } }
/* @gen:keyframes:end */
