/* The homepage's own sections, on top of shared/paper.css.
 *
 * paper.css holds the system every paper page shares: tokens, type, buttons,
 * the section head, device frames, the closing band and the motion primitives.
 * What is here is what only the homepage has: the hero, the three offers, the
 * disciplines strip, the platform tabs, the co-pilot, the claims and pricing.
 */
/* ---------- hero ----------
 * Copy on the left, the photograph on the right bleeding off the top and the
 * right edge, and a rail of words in the right gutter. The photograph's own
 * ground is a near-white studio sweep, so it is multiplied onto the paper and
 * masked on the left: no frame, no visible edge, no scrim. */
/* min-height 100vh so the fold IS the hero: the photograph's floor and the
   bottom of the window are the same line, with no paper strip under her. */
/* overflow:clip, not hidden. `hidden` makes the hero a scroll container, and a
   `view()` timeline on anything inside it then resolves against that container
   instead of the document: the photograph's scroll animation froze at the value
   it happened to hold on load. `clip` clips without establishing a scrollport. */
.hero{position:relative;background:var(--paper);padding-top:80px;overflow:clip;min-height:100vh;min-height:100svh;display:flex;flex-direction:column}
.hero-media{
  /* The frame starts where the header ends, not at the top of the page. The
     photograph's own studio sweep fills its first rows, so that edge is
     invisible, while the hair now clears the bar: overlapping them put a grey
     smudge behind the language pill however the header was painted. */
  /* top and bottom insets rather than a percentage height: whatever the hero
     ends up being, the frame's floor is the hero's floor. */
  position:absolute;top:80px;bottom:0;right:clamp(0px,7vw,124px);
  width:min(42vw,610px);z-index:0;pointer-events:none;
  /* No overflow property here, deliberately. `hidden` makes this a scroll
     container and a `view()` timeline then resolves against IT rather than the
     document, which froze the photograph's scroll animation at whatever value
     it held on load; `clip` behaved the same way in Chrome. Nothing needs
     clipping any more either: the img is exactly 100% of this box at every
     width, and `.hero{overflow:clip}` is the backstop. */
}
/* Two masks, not a scrim: the left one dissolves the photograph into the paper
   behind the headline, the right one hides the crop edge, which lands on the
   mid-grey of a gi sleeve and reads as a printed rectangle without it. */
.hero-media img{
  width:100%;height:100%;object-fit:cover;object-position:54% 0;
  mix-blend-mode:multiply;filter:grayscale(1) contrast(1.11);
  -webkit-mask-image:linear-gradient(90deg,transparent 0%,#000 20%,#000 88%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0%,#000 20%,#000 88%,transparent 100%);
}
/* A short paper fade on the very top row, so the frame's edge cannot draw a
   line if a future crop puts something dark against it. */
.hero-media::after{
  content:"";position:absolute;top:0;left:0;right:0;height:34px;z-index:2;
  background:linear-gradient(180deg,var(--paper) 0%,rgba(243,242,238,0) 100%);
}
/* Newsprint grain. An SVG fractal noise as a background image rather than a CSS
   filter: a filter would have to re-run on every paint of a full-bleed photo,
   this is one tile the compositor reuses. It carries the img's own mask so the
   grain stops exactly where she does and never lands on bare paper. */
.hero-media::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:.62;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.72'/%3E%3C/svg%3E");
  background-size:220px 220px;
  -webkit-mask-image:linear-gradient(90deg,transparent 0%,#000 20%,#000 88%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0%,#000 20%,#000 88%,transparent 100%);
}
/* the words down the right gutter */
/* The veil sits between the photograph and the copy. It is off on a wide
   screen, where she has her own column; on a phone she is behind the words and
   the type needs a clean field to sit on. */
.hero::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;display:none}
.hero-rail{
  position:absolute;right:28px;top:min(20vh,168px);z-index:3;
  display:grid;gap:9px;text-align:right;
}
.hero-rail span{font-family:var(--mono);font-size:10.5px;font-weight:400;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
/* Hidden up to 1260, not 1180: that is where the photograph moves to the edge
   to clear the claim row, and a narrow frame there put her hair under the third
   word, 1.46:1 at 1200x900. */
@media (max-width:1260px){ .hero-rail{display:none} }

/* The wrap is a column so the grid can absorb the slack and the claim row lands
   on the bottom edge of the fold rather than floating above it. */
/* z-index 2, above the veil at 1. At equal z-index the pseudo-element paints
   after its sibling, so the veil went over the headline instead of under it. */
.hero > .wrap{position:relative;z-index:2;display:flex;flex-direction:column;flex:1}
/* The claim row stands off the bottom edge rather than resting on it. Flush,
   it read as something cut off by the viewport instead of a row you land on. */
.hero > .wrap{padding-bottom:clamp(32px,7vh,76px)}
.hero-grid{display:grid;grid-template-columns:minmax(0,.94fr) minmax(0,1.06fr);align-items:center;flex:1}
.hero-copy{padding:24px 0 40px}
.hero-copy .eyebrow{margin-bottom:24px}
.hero h1{max-width:11ch}
.hero .lede{margin:30px 0 40px;max-width:34ch}
.hero-cta{display:flex;flex-wrap:wrap;gap:14px 26px;align-items:center}
.hero-note{margin-top:22px}
/* the claim row across the bottom of the fold: no counts, no vanity numbers */
/* As wide as its three cells and no wider. The photograph's frame starts left
   of where a fixed 600px row ended on anything short of a wide screen, and the
   third cell measured 2.1:1 against a seam in her gi at 1440x900, 1.22:1 at
   1152x720. Text cannot win against a photograph, so the row stops before it. */
.hero-facts{
  display:grid;
  grid-template-columns:repeat(3,auto);justify-content:start;
  gap:0;border-top:1px solid var(--rule);width:fit-content;max-width:100%;
}
.hero-facts div{padding:24px 26px 30px;border-left:1px solid var(--rule)}
.hero-facts div:first-child{border-left:0;padding-left:0}
.hero-facts b{display:block;font-family:var(--serif);font-size:25px;font-weight:300;letter-spacing:-.016em;line-height:1.1}
.hero-facts span{display:block;margin-top:9px;font-family:var(--mono);font-size:10.5px;font-weight:400;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
/* A laptop screen scales her up relative to the page, so her shoulder reaches
   further left: the cells tighten a little and, up to 1260, where the word rail
   is hidden, the frame moves to the edge. Measured 1.67:1 at 1261x1000 and
   1.14:1 at 1200x900 without it. */
@media (min-width:1025px) and (max-width:1366px){
  .hero-facts div{padding:22px 22px 26px}
  .hero-facts b{font-size:23px}
}
@media (min-width:1025px) and (max-width:1260px){
  .hero-media{right:0}
}
@media (max-width:1024px){
  /* She becomes the BACKGROUND rather than a band underneath. The stacked
     version put the photograph below the copy as its own block, which read as
     two unrelated things and cost the fold its subject. Now the frame is
     full-bleed behind everything and the veil below carries the legibility. */
  .hero{padding-top:80px}
  /* The frame stops at the bottom of the FOLD, not the bottom of the hero. Run
     to the hero's floor it continued behind the claim row, which then sat on
     whatever part of the photograph happened to be there: measured 1.0:1
     against her hair at 768 wide. Now her floor is the window's floor and the
     claim row below it is on paper. */
  .hero-media{
    position:absolute;top:80px;bottom:auto;left:0;right:0;width:auto;
    height:calc(100svh - 80px);
  }
  .hero-media img{
    /* Back to 100%. At this frame ratio the source scales by height and fills
       vertically, so the whole portrait shows: her face in the upper half, the
       gi in the lower half. That split is what lets the copy sit under her
       rather than across her. */
    height:100%;object-position:50% 0;
    /* no side masks: at this width there is no paper beside her to dissolve into */
    -webkit-mask-image:none;mask-image:none;
  }
  .hero-media::before{-webkit-mask-image:none;mask-image:none}
  .hero-media::after{display:none}
  /* Paper over her head and shoulders, clearing by the bottom of the fold, so
     the words sit on a clean field and she resolves into a real photograph at
     the bottom edge instead of being flatly faded out. */
  /* No section-wide veil on a phone. A gradient pinned to the fold protects
     whatever happens to be at a given percentage of it, and the copy block's
     height relative to the fold changes with the device: at 390x667 the eyebrow
     rode up into her hair and measured 2.03:1. The wash below travels WITH the
     copy instead, so it is right at every screen height, and her face is left
     as a photograph with nothing over it. */
  .hero::after{display:none}
  .hero-copy{position:relative;isolation:isolate}
  .hero-copy::before{
    content:"";position:absolute;z-index:-1;
    left:-24px;right:-24px;top:-150px;bottom:-40px;
    background:linear-gradient(180deg,
      rgba(243,242,238,0) 0%,
      rgba(243,242,238,.34) 18%,
      rgba(243,242,238,.74) 32%,
      rgba(243,242,238,.90) 52%,
      rgba(243,242,238,.95) 100%);
  }
  /* The grid alone owns the fold, so the claim row lands just under it rather
     than competing for the first screen. */
  .hero-grid{grid-template-columns:minmax(0,1fr);min-height:calc(100svh - 80px);align-items:flex-end}
  /* The empty second column is the desktop layout's spacer. Left in place it
     became a second ROW here and took the slack, so flex-end had nothing to
     push the copy against and it floated in the middle. */
  .hero-grid > div:last-child{display:none}
  /* Anchored to the bottom of the fold, under her chin rather than across her
     eyes. The headline steps down a size to buy the room this costs. */
  .hero-copy{padding:0 0 30px}
  .hero h1{font-size:clamp(38px,10.4vw,52px)}
  .hero .lede{font-size:17.5px;margin:22px 0 30px}
  .hero h1,.hero .lede{max-width:none}
  /* Darker over the photograph. The eyebrow is the smallest type in the fold,
     and the lede measured 3.79:1 at 390x667, where a short screen pushes it
     below the strong part of the veil. The lede's second sentence keeps its
     emphasis through weight now that colour no longer separates them. */
  /* Full ink, both of them. The eyebrow is the first line of the block, which
     puts it where the wash is weakest, and it is 11px: it needs the headroom. */
  .hero .eyebrow{color:var(--ink)}
  .hero .lede{color:var(--ink)}
  .hero .lede .on{font-weight:600}
  /* And the reassurance line comes off the phone fold altogether. It was the
     lowest copy in the block, which put it over the clear part of the
     photograph: 2.94:1 at 390x667 against the darkest pixel behind it. It is
     one fewer line on a small screen, and the same promise is made by the claim
     row directly below the fold and again at the closing CTA. */
  .hero-note{display:none}
  .hero-facts{padding-top:6px}
  /* Below the fold here, clear of her, so the row can span again. Weighted,
     not equal thirds: the first caption is the longest and equal columns
     wrapped it to two lines beside two one-line neighbours. */
  .hero-facts{grid-template-columns:1.18fr 1fr .92fr;width:auto;max-width:min(600px,100%)}
  .hero > .wrap{padding-bottom:0}
}
@media (max-width:600px){
  /* One per row. Two-up put "Software, sites, payments" on two lines beside a
     one-line neighbour and the row stopped reading as a row. */
  .hero-facts{grid-template-columns:1fr;max-width:none}
  .hero-facts div{padding:16px 0;border-left:0;border-top:1px solid var(--rule)}
  .hero-facts div:first-child{border-top:0}
  .hero-facts b{font-size:24px}
  .hero-cta{gap:10px 18px}
}

/* ---------- the disciplines strip ----------
 * The label is pinned and the arts scroll under it, right to left, forever. The
 * track is duplicated in the markup and the keyframe travels exactly -50%, which
 * is what makes the loop seamless; hover pauses it. */
.strip{border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);background:var(--paper);overflow:hidden}
.strip .wrap{display:flex;align-items:center;gap:0;max-width:none;padding:0}
.strip .lbl{
  flex:none;padding:20px 28px 20px 40px;position:relative;z-index:2;background:var(--paper);
  font-family:var(--mono);font-size:10.5px;font-weight:400;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-3);white-space:nowrap;
}
.strip-rail{
  flex:1;min-width:0;overflow:hidden;display:flex;
  /* Only the trailing edge fades. A leading fade put a half-visible letter
     right next to the pinned label and read as a clipping bug. */
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 96px),transparent);
          mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 96px),transparent);
}
.strip-track{display:flex;align-items:center;flex:none;gap:38px;padding-right:38px;animation:marquee 42s linear infinite}
.strip-track span{font-family:var(--serif);font-size:20px;font-weight:300;color:var(--ink-2);white-space:nowrap}
.strip:hover .strip-track{animation-play-state:paused}
@media (max-width:760px){
  .strip .lbl{padding:16px 20px 16px 22px}
  .strip-track{gap:26px;padding-right:26px}
  .strip-track span{font-size:17px}
}

/* ---------- what MatPilot offers: three cards, edge to edge ----------
 * Three products, one anatomy each: eyebrow, heading, one line, one link. The
 * first is ink and carries the app, the second paper and carries the sites, the
 * third is type alone. A white-label app has no honest screenshot (the whole
 * point is that it is not branded MatPilot), and inventing one would be the
 * only dishonest pixel on the page, so that card is given air instead. */
.offer{display:grid;grid-template-columns:1fr 1.18fr .76fr;align-items:stretch}
/* clip, not hidden: this card contains three scroll-driven animations (the copy
   and both visuals) and overflow:hidden would make it their scroll container,
   freezing all three. Same reason as .hero. */
.offer-card{position:relative;overflow:clip;display:flex;flex-direction:column;justify-content:space-between;min-height:min(62vh,560px);padding:46px 42px 0}
.offer-ink{background:var(--dark);color:var(--white)}
.offer-ink .eyebrow{color:rgba(255,255,255,.62)}
.offer-ink .link-arw{color:var(--white);border-bottom-color:rgba(255,255,255,.5)}
.offer-ink .link-arw:hover{border-bottom-color:var(--white)}
.offer-paper{background:var(--paper-2)}
.offer-quiet{background:var(--paper);border-left:1px solid var(--rule);justify-content:flex-start;padding-bottom:46px}
.offer-copy{max-width:30ch}
.offer-card .eyebrow{margin-bottom:18px}
.offer-card h2{font-size:clamp(26px,2.3vw,32px);line-height:1.1;max-width:16ch;text-wrap:balance}
/* the quiet card's CTA is a button, so it needs a little more room above it */
.offer-quiet p{margin-bottom:30px}
.offer-card p{margin:18px 0 24px;font-size:15px;line-height:1.55;letter-spacing:-.006em;color:var(--ink-2);text-wrap:pretty}
/* AFTER .offer-card p, not before it. Declared above, at equal specificity, it
   lost and the ink card's paragraph rendered #4a4a51 on near-black: 2.2:1. */
.offer-ink p{color:rgba(255,255,255,.82)}
.offer-visual{position:relative;margin-top:34px}

/* the app, leaning off the card's right edge. 108% and not more: the cut has to
   land past the last readable column, or it reads as a broken crop. */
.offer-visual--screen{margin:34px -42px -1px 0;border-radius:8px 0 0 0;overflow:clip;box-shadow:0 -22px 60px -26px rgba(0,0,0,.8)}
.offer-visual--screen img{width:108%;max-width:none;display:block}

/* four real sites, fanned up and LEFT from a front card on the right. Each back
   card shows its left edge, which is where every one of these sites keeps its
   logo and headline; fanning right showed right edges instead, and Jaque's is
   a photograph of her rather than her brand. */
.offer-visual--sites{margin:30px 0 0 -42px;height:340px}
.offer-visual--sites .site{
  position:absolute;right:0;bottom:0;width:60%;aspect-ratio:16/10;
  border:1px solid var(--rule-2);border-radius:8px;overflow:hidden;background:var(--white);
  box-shadow:0 18px 40px -22px rgba(0,0,0,.4);
  transition:transform .55s cubic-bezier(.2,.7,.2,1),box-shadow .55s ease;
}
.offer-visual--sites img{width:100%;height:100%;object-fit:cover;object-position:top center}
/* Four deep. Each card clears the one in front by 22% of its own width, which
   is enough of the next site to recognise it, and drops 4% of scale so the deck
   reads as depth rather than as a misaligned grid. */
.site-1{z-index:4;transform:translate(0,0)}
.site-2{z-index:3;transform:translate(-22%,-38px) scale(.96)}
.site-3{z-index:2;transform:translate(-44%,-76px) scale(.92)}
.site-4{z-index:1;transform:translate(-66%,-114px) scale(.88)}
.offer-paper:hover .site-1{transform:translate(3%,10px)}
.offer-paper:hover .site-2{transform:translate(-25%,-48px) scale(.96)}
.offer-paper:hover .site-3{transform:translate(-50%,-94px) scale(.92)}
.offer-paper:hover .site-4{transform:translate(-75%,-140px) scale(.88)}

@media (max-width:1180px){
  .offer{grid-template-columns:1fr 1fr}
  .offer-quiet{grid-column:1/-1;border-left:0;border-top:1px solid var(--rule);min-height:0;padding:46px 42px}
  .offer-quiet .offer-copy{max-width:44ch}
}
@media (max-width:720px){
  .offer{grid-template-columns:1fr}
  .offer-card{padding:36px 22px 0;min-height:0}
  .offer-quiet{padding:36px 22px}
  /* 200% and left-anchored: the whole dashboard at 390px is a grey smear, so a
     phone gets the sidebar and the briefing at a size that can be read. */
  /* The whole screen, not a crop of it. At 200% a phone showed the sidebar and
     half the dashboard and cut the rest off at the edge (Vinny, 11 Sep 2026). */
  .offer-visual--screen{margin:28px 0 -1px;border-radius:8px 8px 0 0}
  .offer-visual--screen img{width:100%}
  .offer-visual--sites{margin:26px 0 0 -22px;height:236px}
  .offer-card h2,.offer-copy{max-width:none}
}

/* ---------- the platform: one laptop, four screens ---------- */
.platform{background:var(--paper)}
.platform-grid{display:grid;grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);gap:64px;align-items:center;padding-top:64px}
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--rule-2);margin-bottom:24px;overflow-x:auto;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tab{
  appearance:none;background:none;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;
  padding:12px 15px;font-size:14px;font-weight:500;letter-spacing:-.01em;color:var(--ink-3);cursor:pointer;white-space:nowrap;
  transition:color .15s ease,border-color .15s ease;position:relative;
}
.tab:first-child{padding-left:0}
.tab:hover{color:var(--ink)}
.tab[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--ink)}
.tab-panel[hidden]{display:none}
.tab-panel p{font-size:17px;line-height:1.6;letter-spacing:-.008em;color:var(--ink-2);max-width:42ch;margin-bottom:28px;text-wrap:pretty}
/* The phone stands in front of the laptop's right corner, dropped below its
   deck, so the two read as one set of devices rather than two pictures. */
.platform-screen{position:relative}
.platform-screen .phone-float{position:absolute;right:-6%;bottom:-8%;width:22%;z-index:2}
@media (max-width:1024px){
  .platform-grid{grid-template-columns:minmax(0,1fr);gap:44px}
  .platform-copy{order:-1}
  /* inside the column now, since there is no gutter to its right to hang into */
  .platform-screen{margin-bottom:40px}
  .platform-screen .phone-float{right:-1%;width:25%}
}

/* ---------- curriculum ---------- */
.curriculum{background:var(--paper-2);border-top:1px solid var(--rule)}

/* ---------- the co-pilot ---------- */
.copilot-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.8fr);gap:72px;align-items:center}
.copilot-copy .eyebrow{margin-bottom:22px}
.copilot-copy h2{max-width:20ch}
.copilot-copy .lede{margin:28px 0 0}
.copilot-copy .lede b{color:var(--ink);font-weight:500}
.copilot-card{position:relative;border-radius:18px;overflow:hidden;background:var(--white);border:1px solid var(--rule);box-shadow:0 40px 80px -44px rgba(0,0,0,.45);max-width:390px;margin:0 auto}
.copilot-note{display:flex;align-items:center;gap:9px;justify-content:center;margin-top:18px;font-size:13.5px;color:var(--ink-3)}
.copilot-note::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--accent);flex:none;animation:pulse 2.6s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.78)}}
@media (max-width:1024px){ .copilot-grid{grid-template-columns:minmax(0,1fr);gap:48px} .copilot-copy h2{max-width:none} }

/* the claims band */
.claims-band{border-top:1px solid var(--rule);background:var(--paper);padding:74px 0}

/* ---------- pricing ---------- */
.pricing{background:var(--paper-2);border-top:1px solid var(--rule)}
.pricing .sol-head{padding-bottom:14px}

/* the fold: still a timed entrance, because nothing has scrolled yet */
.hero-copy > *{animation:rise 1s cubic-bezier(.2,.7,.2,1) both}
.hero-copy .eyebrow{animation-delay:.06s}
.hero-copy h1{animation-delay:.14s}
.hero-copy .lede{animation-delay:.3s}
.hero-copy .hero-cta{animation-delay:.44s}
.hero-copy .hero-note{animation-delay:.56s}
.hero-media{animation:photoIn 1.5s .1s cubic-bezier(.2,.7,.2,1) both}
.hero-rail span,.hero-facts div{animation:rise .9s .7s cubic-bezier(.2,.7,.2,1) both}
.hero-facts div:nth-child(2){animation-delay:.78s}
.hero-facts div:nth-child(3){animation-delay:.86s}

/* ---- pointer feedback ---- */
.offer-card{transition:background .4s ease}
.offer-visual--screen img{transition:transform .7s cubic-bezier(.2,.7,.2,1)}
.offer-ink:hover .offer-visual--screen img{transform:translateY(-10px) scale(1.015)}
.offer-paper:hover .site{box-shadow:0 -18px 46px -18px rgba(0,0,0,.5)}
.tab{position:relative}
.tab::after{content:"";position:absolute;left:0;bottom:-2px;height:2px;width:0;background:var(--accent)}
.tabs.is-auto .tab[aria-selected="true"]::after{animation:tabTimer 4.6s linear both}
.tab-panel p{animation:rise .5s cubic-bezier(.2,.7,.2,1) both}

/* ---- the JS fallback's two compound reveals ---- */
.frame{perspective:1600px}
[data-reveal].platform-screen,[data-reveal].copilot-demo{opacity:1;transform:none}
.platform-screen .frame{opacity:0;transform:rotateX(11deg) translateY(38px);transform-origin:50% 100%;transition:transform 1.2s cubic-bezier(.2,.7,.2,1),opacity 1s ease}
.platform-screen.is-in .frame{opacity:1;transform:none}
.platform-screen .phone{opacity:0;transform:translateY(40px);transition:opacity .9s ease .25s,transform 1.1s cubic-bezier(.2,.7,.2,1) .25s}
.platform-screen.is-in .phone{opacity:1;transform:none}
.copilot-demo .copilot-card{opacity:0;transform:translateY(26px);transition:opacity .8s ease,transform 1s cubic-bezier(.2,.7,.2,1)}
.copilot-demo.is-in .copilot-card{opacity:1;transform:none}

/* ---- scroll-driven: the same reveals, tied to the scroll instead of a timer ----
 * `animation-range` is quoted in view-progress units: `entry 25%` is the moment
 * the element is a quarter of the way into the viewport, `cover 60%` is 60% of
 * the way through crossing it.
 *
 * These ranges start LATER than a conventional reveal and finish before the
 * middle of the crossing. The first pass began at `entry 6%` and was done by
 * `cover 34%`, which meant a block had settled while it was still near the
 * bottom of the window and nothing was moving by the time you read it. Pushing
 * the end past the middle instead left content half-faded while it was already
 * legible, which is worse. So the reveals are late and quick, and the constant
 * motion comes from the DRIFT layer below, which never finishes at all.
 *
 * Anything marked DRIFT runs across the element's entire crossing
 * (`cover 0% cover 100%`), so it never finishes while it is on screen.
 */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .offer-card[data-reveal-delay="1"]{animation-range:entry 24% cover 50%}
    .offer-card[data-reveal-delay="2"]{animation-range:entry 30% cover 56%}


    /* The drift and the reveal go on DIFFERENT elements on purpose. Stacked on
       one, they both animate `transform` and the later one simply replaces the
       earlier: the measured result was a card that moved into place and then sat
       perfectly still for the rest of its crossing. Outer element drifts for the
       whole crossing, inner element reveals once. */
    .platform-screen{animation:driftUp linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    .platform-screen .frame,.platform-screen.is-in .frame{
      opacity:1;transition:none;
      animation:tiltIn linear both;animation-timeline:view();animation-range:entry 12% cover 42%;
    }
    /* The phone runs faster than the laptop it stands in front of, so the pair
       has depth as it crosses: wrapper drifts, the phone itself arrives late. */
    .platform-screen .phone-float{animation:phoneDrift linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    .platform-screen .phone,.platform-screen.is-in .phone{
      opacity:1;transition:none;
      animation:liftIn linear both;animation-timeline:view();animation-range:entry 20% cover 50%;
    }
    .copilot-demo{animation:driftUp linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    .copilot-demo .copilot-card,.copilot-demo.is-in .copilot-card{
      opacity:1;transition:none;
      animation:liftIn linear both;animation-timeline:view();animation-range:entry 16% cover 46%;
    }



    /* DRIFT: the two screenshots move against the page for their whole crossing */
    .offer-visual--screen img{animation:driftY linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    .offer-ink:hover .offer-visual--screen img{animation-play-state:paused}
    .offer-visual--sites{animation:driftUpSmall linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    /* the photograph closes in as the fold leaves: a ken burns whose clock is
       the scroll, so it only ever moves while the reader is moving */
    .hero-media img{animation:heroPush linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
    /* The fold leaves before the page does: the type lifts and fades from the
       first flick while the photograph lags behind it, so the parallax is
       between the two rather than against the page.
       `scroll(root)` and not `view()`: a view timeline measures a subject
       crossing the viewport, and the hero starts already filling it, so every
       view range is degenerate here (`exit` begins and ends at the same scroll
       offset). The document's own scroll offset is the honest clock for a fold. */
    .hero-copy{animation:foldOut linear both;animation-timeline:scroll(root);animation-range:0 64vh}
    .hero-rail{animation:railOut linear both;animation-timeline:scroll(root);animation-range:0 42vh}
    /* On a desktop the claim row is IN the fold, so it keeps its timed entrance
       and leaves with the fold, a beat behind the copy. A view() reveal here
       was measured from the moment the row entered, which is page load: the
       first screen showed it at 0.1 to 0.2 opacity and it only resolved once
       you scrolled. On a phone it sits just under the fold, where a scroll
       reveal is what it is for. Container and cells take one each, since two
       animations on the same `transform` replace each other. */
    .hero-facts{animation:foldOut linear both;animation-timeline:scroll(root);animation-range:6vh 70vh}
    @media (max-width:1024px){
      .hero-facts{animation:none}
      .hero-facts > div{animation:stepIn linear both;animation-timeline:view();animation-range:entry 30% cover 52%}
      .hero-facts > div:nth-child(2){animation-range:entry 36% cover 58%}
      .hero-facts > div:nth-child(3){animation-range:entry 42% cover 64%}
    }
    /* the offer copy rides a little slower than the card it sits in */
    .offer-copy{animation:driftUpSmall linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
  }
}
@media (prefers-reduced-motion:reduce){
  .hero-copy > *,.hero-media,.hero-rail span,.hero-facts div,.tab-panel p,
  .strip-track,.copilot-note::before{animation:none}
  .platform-screen .frame,.platform-screen .phone{opacity:1;transform:none;transition:none}
  .copilot-demo .copilot-card{opacity:1;transform:none;transition:none}
  .offer-visual--screen img,.site{transition:none}
  .btn:active{transform:none}
}
