/* ============================================================================
   RevelPics — landing page

   Loaded only by home.html, on top of style.css and luxe.css. Nothing here may
   redefine a colour token (theme.js owns colours as inline styles on <html>).
   Geometry and layout only.
   ========================================================================== */

.nav-signin{width:auto;margin:0 0 0 auto}

/* The landing page's own brand bar. Every other page keeps the 720px column its
   content uses, and so did this one until the hero grew a second column: a bar
   centered on 720 while the hero runs to 1180 leaves the logo indented a couple of
   hundred pixels from the hero beneath it, which reads as a mistake rather than as a
   margin. The bar now matches the hero's own container exactly, so the mark and
   "Sign in" line up with the edge of the copy column and the edge of the photograph.
   landing.css is loaded by home.html only, so nothing else is affected. */
.topbar{max-width:1180px;padding:var(--s-4) var(--s-4) 0}

/* ============================================================ hero
   Two columns: the pitch, and the product photographed where a guest actually meets
   it, a code on a card in the middle of a set table. That photograph is the only
   thing on the page that answers "what does my guest see?", and it is why the hero
   is the one section that runs wider than the page's own text column: two columns of
   readable copy plus a portrait photograph do not fit in 720px. It is the widest
   thing on the page deliberately.

   Geometry only, no colour tokens (theme.js owns colours as inline styles on <html>),
   so the accent that draws the eyebrow is the album's own accent.

   The photograph is 2:3 and the column is capped at 520px, which puts the code on the
   card at about 130px on a desktop wide enough for two columns: comfortably scannable
   from the screen, and the same code that is printed on the sign in the pack. */
.land-hero{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,520px);
  gap:clamp(var(--s-5),4vw,var(--s-7));align-items:center;
  width:min(1180px,100%);margin:0 auto;
  padding:var(--s-6) var(--s-4);
}
.land-hero .hero-copy{min-width:0}
.land-hero .eyebrow{
  font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.14em;
  font-weight:700;color:var(--accent-text);margin:0 0 var(--s-3);
}
.land-hero h1{
  font-size:clamp(2.15rem,3.6vw,3.4rem);line-height:1.08;letter-spacing:-.02em;
  /* 20ch, the same measure the centred version used: the headline is 41 characters,
     so at this width it makes three lines rather than four, with no word left alone
     on the last one. */
  margin:0 0 var(--s-4);max-width:20ch;
}
.land-hero .lead{
  font-size:var(--t-lg);color:var(--dim);line-height:1.6;
  max-width:48ch;margin:0 0 var(--s-4);
}
/* The tagline from the logo lockup, letterspaced the way the artwork sets it, as
   the last line of the pitch before the buttons. */
.land-hero .slogan{
  margin:0 0 var(--s-5);
  font-size:.78rem;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:var(--accent-text);
}
.cta-row{
  display:flex;gap:var(--s-3);flex-wrap:wrap;
  margin-bottom:var(--s-4);
}
.cta-row .btn{width:auto;margin:0;min-width:180px}
.land-hero .tiny{font-size:var(--t-sm);color:var(--dim);margin:0}

/* The photograph: the app's own raised-panel radius and its float shadow, so the
   frame matches the cards below instead of inventing a third look. */
.land-hero .hero-shot{margin:0}
.land-hero .hero-shot img{
  display:block;width:100%;height:auto;
  border-radius:var(--lux-r-lg);box-shadow:var(--lux-sh-3);
}
/* The rating line, when there is one to show: the slot the hero leaves for real
   reviews, dropped in under the price note. Nothing renders here until the storefront
   has the numbers, and it is deliberately not in the template as a placeholder. */
.land-hero .trust{
  display:flex;align-items:center;gap:9px;
  margin:var(--s-4) 0 0;font-size:var(--t-sm);color:var(--dim);
}
.land-hero .trust .stars{color:#E0A33E;letter-spacing:2px}

/* Between a phone and a full laptop, the photograph gives up width before the copy
   does. At 1024 the two columns would otherwise be 416px of text beside 520px of
   picture, which reads as a photo with a caption rather than as a page with a hero. */
@media (max-width:1140px){
  .land-hero{grid-template-columns:minmax(0,1fr) minmax(0,440px)}
}

/* One column: the copy first, the photograph under it, capped so a phone does not get
   a full-bleed portrait that pushes the buttons off the fold. */
@media (max-width:940px){
  .land-hero{grid-template-columns:1fr;gap:var(--s-5);padding:var(--s-5) var(--s-4)}
  .land-hero h1{max-width:22ch}
  .land-hero .hero-shot{max-width:520px;margin:0 auto}
}

/* ============================================================ sections */
.land-sec{margin-top:var(--s-7);scroll-margin-top:var(--s-6)}
.land-sec > h2{
  font-size:var(--t-xs);color:var(--accent-text);text-align:center;
  margin:0 0 var(--s-5);
}

/* ============================================================ how it works */
.steps{
  list-style:none;padding:0;margin:0;
  display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4);
  counter-reset:none;
}
.steps li{
  background:var(--panel);border-radius:var(--lux-r-lg);
  padding:var(--s-5);box-shadow:var(--lux-sh-1);
}
.steps .step-n{
  display:inline-grid;place-items:center;
  width:34px;height:34px;border-radius:50%;margin-bottom:var(--s-3);
  font-family:var(--font-display);font-size:var(--t-lg);font-weight:600;
  background:var(--accent);color:var(--accent-ink);
  box-shadow:0 4px 12px var(--accent-soft);
}
.steps b{display:block;font-size:var(--t-base);font-weight:680;margin-bottom:var(--s-2)}
.steps p{margin:0;color:var(--dim);font-size:var(--t-sm);line-height:1.6}

/* ============================================================ features */
.featgrid{
  display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s-4);
}
.feat{
  background:var(--panel);border-radius:var(--lux-r-lg);
  padding:var(--s-5);box-shadow:var(--lux-sh-1);
}
.feat b{display:block;font-size:var(--t-base);font-weight:680;margin-bottom:var(--s-2)}
.feat p{margin:0;color:var(--dim);font-size:var(--t-sm);line-height:1.6}

/* ============================================================ perfect for
   The band above says what the product DOES; this says who it is FOR: the eight
   events a buyer recognises themselves in, in the order the marketing pack names
   them. It replaced a six-photo strip of the demo album's own tiles, which showed
   the product's output but never named a single occasion.

   Four across on the page's own 728px column, two on a phone. The name sits ON the
   photograph, over a gradient, rather than underneath it: a caption below the tile
   wraps to two lines on the longer names and then one tile is taller than its
   neighbours, which is the thing that makes a grid read as broken. The tiles are a
   fixed 3:2 and every image is already baked to that shape (640x427), so
   object-fit has nothing to crop and the frame cannot shift as pictures load. */
.land-perfect .perfectgrid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s-2);
}
.land-perfect .pcard{
  position:relative;margin:0;overflow:hidden;
  border-radius:12px;background:var(--panel-2);aspect-ratio:3/2;
}
.land-perfect .pcard img{width:100%;height:100%;object-fit:cover;display:block}
.land-perfect .pcard figcaption{
  position:absolute;left:0;right:0;bottom:0;
  padding:1.8rem .5rem .6rem;
  font-size:1rem;font-weight:650;line-height:1.25;text-align:center;
  text-wrap:balance;
  color:#fff;text-shadow:0 1px 5px rgba(18,12,10,.8);
  background:linear-gradient(180deg,rgba(18,12,10,0),rgba(18,12,10,.72));
}
@media (max-width:680px){.land-perfect .perfectgrid{grid-template-columns:repeat(2,1fr)}}

/* ============================================================ pricing */
.homepage #plans .plan-outcomes{list-style:none;margin:14px 0;padding:0;font-size:13px;font-weight:400;line-height:1.5;color:var(--ink);text-align:left}
.homepage #plans .plan-outcomes li{position:relative;padding-left:16px;margin:0 0 8px;overflow-wrap:anywhere}
.homepage #plans .plan-outcomes li::before{content:"\2713";position:absolute;left:0;color:var(--accent-text)}
.homepage #plans .site-plan-print-note{font-size:14px;line-height:1.6;margin:18px 0;color:var(--ink);max-width:760px}
.homepage #plans .plan-print-included{font-size:13px;line-height:1.5;color:var(--dim);margin:14px 0}
/* What a buyer needs to know before paying, and both halves of it were already true:
   the album's clock runs from the event date, and the refund policy refunds an unused
   album inside the window. Saying them here is the difference between a price and an
   offer. */
.promise{
  margin:var(--s-4) 0 0;padding:var(--s-4) var(--s-4);
  background:var(--panel);border-radius:var(--lux-r-lg);font-size:var(--t-sm);
  color:var(--dim);line-height:1.55;
}
.footc{margin:var(--s-2) 0 0;font-size:var(--t-xs);color:var(--dim)}

/* The plan count drives the columns, because the page's text column is only about
   730px and four cards in one row would be 170px each: too narrow for a price and a
   bullet list. Two by two keeps every card readable and still lets "Most popular"
   stand out. Three plans keep the single row they have always had. */
.pricegrid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4);
  align-items:stretch;
}
.pricegrid.cols-4{grid-template-columns:repeat(2,1fr)}
.pricecard{
  display:flex;flex-direction:column;position:relative;
  background:var(--panel);border-radius:var(--lux-r-lg);
  padding:var(--s-5);box-shadow:var(--lux-sh-1);
}
.pricecard .pname{
  margin:0 0 var(--s-1);font-size:var(--t-lg);font-weight:680;line-height:1.2;
}
.pricecard .ptag{
  margin:0 0 var(--s-4);color:var(--dim);font-size:var(--t-sm);
}
/* The badge is a corner ribbon rather than a pill in the flow, so all three
   cards start at the same height and the prices line up across them. */
.ribbon{
  position:absolute;top:0;right:0;
  background:var(--accent-soft);color:var(--accent-text);
  font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.09em;
  font-weight:700;padding:.3rem .8rem;
  border-radius:0 var(--lux-r-lg) 0 var(--lux-r-lg);
}
.pricecard.featured{
  box-shadow:var(--lux-sh-2);
  outline:2px solid var(--accent);outline-offset:-2px;
}
.pricecard .tag{
  align-self:flex-start;
  font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em;
  font-weight:700;color:var(--dim);
  background:var(--panel-2);border-radius:var(--radius-pill);
  padding:.22rem .7rem;margin-bottom:var(--s-3);
}
.pricecard.featured .tag{background:var(--accent-soft);color:var(--accent-text)}
.pricecard .amount{
  font-family:var(--font-display);font-size:var(--t-3xl);font-weight:400;
  line-height:1;margin:0 0 var(--s-2);
}
.pricecard .pnote{margin:0 0 var(--s-2);color:var(--dim);font-size:var(--t-sm)}
.pricecard .pkeep{margin:0 0 var(--s-4);font-size:var(--t-sm);line-height:1.5}
.pricecard .btn{width:100%}
.plist{list-style:none;padding:0;margin:0 0 var(--s-5);flex:1}
.plist li{
  position:relative;padding:0 0 var(--s-2) 26px;
  font-size:var(--t-sm);line-height:1.5;
}
.plist li::before{
  content:"\2713";position:absolute;left:0;top:0;
  color:var(--accent-text);font-weight:700;
}
.pricecard .btn{margin-top:auto}

/* Everything the three plans share. Shown once, under the cards, because the
   plans genuinely do not differ by feature: only by how long the album is kept. */
.included{
  margin-top:var(--s-5);background:var(--panel);
  border-radius:var(--lux-r-lg);padding:var(--s-5);
  box-shadow:var(--lux-sh-1);
}
.included b{display:block;margin-bottom:var(--s-3);font-size:var(--t-base)}
.included .plist{flex:none;margin-bottom:0;columns:2;column-gap:var(--s-5)}
.included .plist li{break-inside:avoid}
.included .tiny{margin:var(--s-4) 0 0;color:var(--dim);font-size:var(--t-xs);line-height:1.6}

/* ============================================================ faq */
.faq{
  background:var(--panel);border-radius:var(--lux-r-lg);
  box-shadow:var(--lux-sh-1);overflow:hidden;
}
.faq details{border-bottom:1px solid var(--line-soft)}
.faq details:last-child{border-bottom:0}
.faq summary{
  cursor:pointer;padding:var(--s-4) var(--s-5);
  font-weight:650;font-size:var(--t-base);list-style:none;
  display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"+";font-family:var(--font-display);font-size:var(--t-xl);
  color:var(--accent-text);line-height:1;flex:none;
}
.faq details[open] summary::after{content:"\2013"}
.faq p{margin:0;padding:0 var(--s-5) var(--s-4);color:var(--dim);
       font-size:var(--t-sm);line-height:1.65}

/* ============================================================ demo album
   The try-it section on the landing page. The QR sits on its own white tile:
   a code printed on a dark panel loses its quiet zone and stops scanning, which
   is the difference between "try it" and "it does not work". */
.land-demo .lead{margin-bottom:var(--s-5)}
.democard{
  display:grid;grid-template-columns:auto 1fr;gap:var(--s-5);align-items:center;
  background:var(--panel);border-radius:var(--lux-r-lg);padding:var(--s-5);
  box-shadow:var(--lux-sh-1);max-width:680px;margin:0 auto;
}
.demoqr{
  width:176px;height:176px;display:block;background:#fff;
  padding:12px;border-radius:14px;
}
.demotext{min-width:0}
.demourl{margin:0 0 var(--s-2);font-size:var(--t-sm);word-break:break-all}
.demourl a{color:var(--accent-text);font-weight:640}
.demotext .tiny{color:var(--dim);font-size:var(--t-sm);margin:0}
.demolist{list-style:none;margin:var(--s-3) 0 0;padding:0}
.demolist li{
  display:flex;gap:9px;font-size:var(--t-sm);color:var(--dim);
  line-height:1.5;margin-bottom:5px;
}
.demolist li::before{
  content:"";flex:none;width:6px;height:6px;border-radius:50%;
  background:var(--accent);margin-top:.55em;
}
.demonote{
  text-align:center;font-size:var(--t-sm);color:var(--dim);
  max-width:48ch;margin:var(--s-4) auto 0;
}
@media (max-width:680px){
  .democard{grid-template-columns:1fr;justify-items:center;text-align:center}
  .demolist li{justify-content:center;text-align:left}
}

/* ==================================================== floating demo code
   The corner QR, for a visitor reading the page on a laptop who never scrolls as
   far as the demo section. Desktop only: a phone cannot scan its own screen, and
   on a narrow window the widget would sit on top of the content. The script
   reveals it once the hero is behind the visitor and remembers a dismissal. */
.qrdock{
  position:fixed;left:var(--s-5);bottom:var(--s-5);z-index:40;
  width:192px;padding:13px 13px 11px;
  background:#fff;border-radius:var(--lux-r-lg);
  box-shadow:var(--lux-sh-2);
  display:flex;flex-direction:column;align-items:center;gap:7px;
  opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity .28s var(--lux-ease),transform .28s var(--lux-ease);
}
.qrdock.on{opacity:1;transform:none;pointer-events:auto}
.qrdockimg{width:128px;height:128px;display:block;border-radius:10px}
.qrdockt{margin:0;font-size:.76rem;line-height:1.4;color:var(--dim);text-align:center}
.qrdockl{font-size:.78rem;font-weight:650;color:var(--accent-text);text-decoration:none}
.qrdockl:hover{text-decoration:underline}
.qrdockx{
  position:absolute;top:6px;right:6px;width:24px;height:24px;
  display:grid;place-items:center;padding:0;margin:0;
  background:var(--panel-2);color:var(--dim);
  border:0;border-radius:50%;font-size:15px;line-height:1;cursor:pointer;
}
.qrdockx:hover{background:var(--line);color:var(--ink)}
@media (max-width:1000px){.qrdock{display:none}}

/* ============================================================ footer
   One line about the product, then the site's own links. The brand lockup, the
   three policies and the merchant-of-record line all live in the shared legal
   footer immediately below, so none of them is repeated here. */
.footbrand{margin:var(--s-7) 0 0;text-align:center}
.foottag{color:var(--dim);font-size:.9rem;margin:0 auto var(--s-5);max-width:46ch}
.footnav{display:flex;flex-wrap:wrap;justify-content:center;gap:10px 28px;font-size:.9rem}
.footnav a{color:var(--ink);text-decoration:none}
.footnav a:hover{color:var(--accent-text);text-decoration:underline}

/* ============================================================ responsive */
@media (max-width:980px){
  /* Three price cards get cramped before the phone breakpoint does. */
  .pricegrid{grid-template-columns:1fr}
  .included .plist{columns:1}
}
@media (max-width:680px){
  .steps{grid-template-columns:1fr}
  .featgrid{grid-template-columns:1fr}
  .pricegrid{grid-template-columns:1fr}
  .land-hero{padding:var(--s-5) var(--s-4) var(--s-6)}
}

/* ============================================================ Snap Scan Share
   The guest's three steps as one CSS animation on a 7.2 second loop. No video and no
   library: the only downloads are the four photographs, which are the marketing
   pack's own AI-rendered set (band-album-1..3 are already in the album, band-shoot
   is the one being taken and then landing in it).

   7.2s, not 9s: the same sequence run a quarter faster, on the owner's note that the
   loop read as slow. Every step's share of the cycle is a percentage, so changing
   the one duration here speeds the whole band up together and no keyframe moves.

   Colours come only from tokens, so a themed album still renders this correctly,
   and the device bezel deliberately uses --ink rather than a hardcoded near-black.

   The loop pauses while the band is off screen (html.band-gated is set by the page
   script, .live is toggled by an IntersectionObserver) and is switched off entirely
   under prefers-reduced-motion, where the finished frame is what shows. */
.land-band{margin-top:var(--s-7)}
.bandhead{margin:0 auto var(--s-5);text-align:center}
.bandhead .kicker{
  font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.2em;
  font-weight:700;color:var(--accent-text);margin:0 0 var(--s-3);
}
.bandhead h2{
  /* The page's own h2 rule is the small rose section label (uppercase, --dim).
     This line is the band's headline, the mirror of the hero's h1, so it is set
     explicitly: display serif, sentence case, ink. Without saying all four, the
     global rule wins and "Snap. Scan. Share." renders as grey capitals. */
  font-family:var(--font-display);font-weight:400;text-transform:none;
  letter-spacing:-.01em;color:var(--ink);
  font-size:clamp(1.6rem,4vw,2.1rem);line-height:1.12;
  margin:0 auto var(--s-3);max-width:24ch;
}
.bandhead .lead{margin:0 auto;max-width:52ch}
.threeup{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4)}
.threeup .stepcard{
  background:var(--panel);border-radius:var(--lux-r-lg);box-shadow:var(--lux-sh-1);
  padding:var(--s-4) var(--s-4) var(--s-5);text-align:center;
}
.threeup .step-n{
  margin:0;font-size:.7rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent-text);
}
.threeup h3{font-size:1.45rem;margin:var(--s-2) 0 var(--s-2)}
.threeup .stepcard p:last-child{margin:0;color:var(--dim);line-height:1.55;font-size:.94rem}
.land-band .bandnote{text-align:center;margin:var(--s-4) 0 0}

.stage{
  position:relative;height:230px;margin:0 0 var(--s-4);overflow:hidden;
  border-radius:var(--radius-sm);
  background:linear-gradient(180deg,var(--panel),var(--bg-tint));
}

/* --- the phone prop --- */
.stage .phone{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:118px;height:196px;padding:7px;border-radius:22px;background:var(--ink);
  box-shadow:0 12px 26px rgba(0,0,0,.22);
}
.stage .phone .scr{
  position:relative;width:100%;height:100%;overflow:hidden;border-radius:16px;
  background:var(--bg-tint);
}
.stage .phone .vf{width:100%;height:100%;object-fit:cover;display:block}
.stage .cnr{
  position:absolute;width:16px;height:16px;border:2px solid rgba(255,255,255,.9);
  border-radius:3px;
}
.stage .cnr.c1{top:12px;left:12px;border-right:0;border-bottom:0}
.stage .cnr.c2{top:12px;right:12px;border-left:0;border-bottom:0}
.stage .cnr.c3{bottom:12px;left:12px;border-right:0;border-top:0}
.stage .cnr.c4{bottom:12px;right:12px;border-left:0;border-top:0}
.stage .shutter{
  position:absolute;left:50%;bottom:12px;transform:translateX(-50%);
  width:26px;height:26px;border-radius:50%;background:var(--panel);
  box-shadow:inset 0 0 0 3px rgba(0,0,0,.18);
}
.stage .shutter i{
  position:absolute;inset:4px;border-radius:50%;background:var(--accent);
  animation:rp-shutter 7.2s infinite both;
}
.stage .flash{
  position:absolute;inset:0;background:#fff;opacity:0;
  animation:rp-flash 7.2s infinite both;
}
.stage .shot{
  position:absolute;left:50%;top:50%;width:74px;height:74px;padding:3px;
  border-radius:8px;background:var(--panel);
  box-shadow:0 6px 14px rgba(0,0,0,.25);
  transform:translate(-50%,-50%) scale(.4);opacity:0;
  animation:rp-shot 7.2s infinite both;
}
.stage .shot img{width:100%;height:100%;object-fit:cover;border-radius:5px;display:block}
@keyframes rp-shutter{
  0%,6%{transform:scale(1)}9%{transform:scale(.78)}13%{transform:scale(1)}100%{transform:scale(1)}
}
@keyframes rp-flash{
  0%,8%{opacity:0}10%{opacity:.92}16%{opacity:0}100%{opacity:0}
}
@keyframes rp-shot{
  0%,7%{opacity:0;transform:translate(-50%,-50%) scale(.4)}
  14%{opacity:1;transform:translate(-50%,-50%) scale(1.06)}
  22%{transform:translate(-50%,-50%) scale(1)}
  92%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-50%) scale(.92)}
}

/* --- the code on the table --- */
.stage .qrtile{
  position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);
  width:132px;height:132px;padding:12px;border-radius:12px;background:var(--qr-bg);
  box-shadow:0 8px 20px rgba(0,0,0,.16);
}
.stage .qrtile img{width:100%;height:100%;display:block}
/* No demo album means no slug to encode, so the tile shows a code-like pattern
   rather than a broken image. It is never scanned, only looked at. */
.stage .qrtile:not(:has(img)){
  background-image:repeating-linear-gradient(90deg,var(--ink) 0 6px,transparent 6px 12px);
  background-size:100% 100%;opacity:.85;
}
.stage .scanline{
  /* Kept to the width of the code it is sweeping, not the width of the card: at
     card width the line reads as a rule across the panel rather than a scan. */
  position:absolute;left:50%;margin-left:-66px;width:132px;height:3px;top:52px;
  border-radius:2px;
  background:linear-gradient(90deg,rgba(206,109,124,0),var(--accent) 20%,var(--accent) 80%,rgba(206,109,124,0));
  box-shadow:0 0 12px rgba(206,109,124,.75);
  animation:rp-scan 7.2s infinite both;
}
@keyframes rp-scan{
  0%,34%{opacity:0;top:52px}42%{opacity:1}
  60%{opacity:1;top:170px}66%{opacity:0;top:170px}100%{opacity:0}
}
.stage .detected{
  position:absolute;left:50%;top:46%;width:150px;height:150px;border-radius:16px;
  transform:translate(-50%,-50%) scale(.86);opacity:0;
  box-shadow:0 0 0 3px var(--accent),0 0 0 9px rgba(206,109,124,.16);
  animation:rp-det 7.2s infinite both;
}
@keyframes rp-det{
  0%,58%{opacity:0;transform:translate(-50%,-50%) scale(.86)}
  64%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  88%{opacity:1}100%{opacity:0}
}
.stage .check{
  position:absolute;left:50%;top:46%;width:44px;height:44px;border-radius:50%;
  background:var(--accent);color:var(--accent-ink);
  display:grid;place-items:center;font-size:22px;font-weight:700;
  transform:translate(-50%,-50%) scale(.5);opacity:0;
  animation:rp-chk 7.2s infinite both;
}
@keyframes rp-chk{
  0%,64%{opacity:0;transform:translate(-50%,-50%) scale(.5)}
  70%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  88%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-50%) scale(.9)}
}

/* --- it lands in the album --- */
.stage .minigrid{
  position:absolute;left:50%;top:18px;transform:translateX(-50%);
  display:grid;grid-template-columns:repeat(4,1fr);gap:5px;width:150px;
}
.stage .minigrid img{
  display:block;width:100%;height:auto;aspect-ratio:1;object-fit:cover;border-radius:4px;
}
.stage .minigrid .on{opacity:0;animation:rp-pop 7.2s infinite both}
@keyframes rp-pop{
  0%,84%{opacity:0;transform:scale(.7)}
  90%{opacity:1;transform:scale(1.12)}96%{transform:scale(1)}100%{opacity:1}
}
.stage .flyer{
  position:absolute;left:50%;bottom:34px;width:64px;height:64px;padding:3px;
  border-radius:8px;background:var(--panel);opacity:0;
  box-shadow:0 8px 18px rgba(0,0,0,.22);
  animation:rp-fly 7.2s infinite both;
}
.stage .flyer img{width:100%;height:100%;object-fit:cover;border-radius:5px;display:block}
@keyframes rp-fly{
  0%,64%{opacity:0;transform:translateX(-50%) translateY(0) scale(.9)}
  70%{opacity:1;transform:translateX(-50%) translateY(-8px) scale(1)}
  84%{opacity:1;transform:translateX(-50%) translateY(-78px) scale(.72)}
  92%{opacity:0;transform:translateX(-50%) translateY(-96px) scale(.6)}
  100%{opacity:0}
}
.stage .bar{
  position:absolute;left:32px;right:32px;bottom:26px;height:7px;border-radius:99px;
  background:var(--line);overflow:hidden;
}
.stage .bar i{
  display:block;height:100%;width:0;border-radius:99px;background:var(--accent);
  animation:rp-fill 7.2s infinite both;
}
@keyframes rp-fill{
  0%,64%{width:0}86%{width:100%}92%{width:100%}100%{width:0;opacity:0}
}
.stage .pct{
  position:absolute;left:0;right:0;bottom:40px;margin:0;text-align:center;
  font-size:.72rem;font-weight:600;color:var(--dim);opacity:0;
  animation:rp-pct 7.2s infinite both;
}
@keyframes rp-pct{
  0%,66%{opacity:0}72%{opacity:1}92%{opacity:1}100%{opacity:0}
}

/* Off screen the loop waits, so a visitor reading the top of the page is not
   running five animations behind their back. */
html.band-gated .land-band:not(.live) .stage *{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){
  .land-band .stage *{animation:none!important}
  .land-band .shot,.land-band .flyer,.land-band .check,
  .land-band .detected,.land-band .minigrid .on{opacity:1!important}
  .land-band .bar i{width:100%!important}
}

@media (max-width:760px){
  .threeup{grid-template-columns:1fr}
  .threeup .stepcard{display:grid;grid-template-columns:120px 1fr;gap:var(--s-4);
    align-items:center;text-align:left;padding:var(--s-4)}
  .threeup .stepcard .stage{height:120px;margin:0}
  .threeup .stepcard h3{font-size:1.2rem;margin:2px 0 4px}
  .stage .phone{width:62px;height:104px;padding:4px;border-radius:14px}
  .stage .phone .scr{border-radius:9px}
  .stage .cnr{width:9px;height:9px;border-width:1px}
  .stage .cnr.c1{top:7px;left:7px}.stage .cnr.c2{top:7px;right:7px}
  .stage .cnr.c3{bottom:7px;left:7px}.stage .cnr.c4{bottom:7px;right:7px}
  .stage .shutter{width:16px;height:16px;bottom:7px;box-shadow:inset 0 0 0 2px rgba(0,0,0,.18)}
  .stage .shot{width:40px;height:40px;padding:2px}
  .stage .qrtile{width:76px;height:76px;padding:7px}
  .stage .detected{width:88px;height:88px;border-radius:12px}
  .stage .check{width:28px;height:28px;font-size:15px}
  .stage .minigrid{width:92px;top:8px;gap:3px}
  .stage .flyer{width:34px;height:34px;bottom:22px}
  .stage .bar{left:20px;right:20px;bottom:16px;height:5px}
  .stage .pct{bottom:26px;font-size:.62rem}
  .stage .scanline{margin-left:-38px;width:76px}
}
