/* Vantical, landing hero v2 + the quiet pages (prepare, privacy).
   Loads after preview.css and speaks its language: same tokens, same layer
   order, no new colours and no new radius. The layer names below join the
   layers preview.css already declared, so the discipline holds. */

/* ===================================================== COMPONENTS ========= */
@layer components {

  /* ---------------------------------------------------------- hero2 ------
     The claim holds the centre of the first viewport. Photo cards float
     down both gutters, absolutely positioned and clipped so they can never
     move layout or cross the centre column. */
  .hero2 {
    position: relative;
    overflow: clip;
    display: grid;
    place-items: center;
    /* Symmetric, so place-items actually centres the message. The scroll
       hint is taken out of flow below and lives in the bottom padding. */
    padding-block: clamp(3.5rem, 7vh, 5rem);

    /* The hero runs its own display size. --t-hero stays where it is because
       index.html still reads it. The vh term only binds on a short wide
       screen, where the stack would otherwise push the button towards the
       fold.

       Raised 20% in round 7, from a 3.25rem cap to 3.9rem, and another 10%
       in round 9, to 4.3rem. The cap is set to stop line two of the claim
       ("worth of jobs in 90 days.", 25 characters, the same count the old
       line ran to) growing wider than the gutter the photo columns live in.
       That constraint has not gone away, it is paid for: --claim-w below
       tracks this size and was widened with it, and the cards give up the
       width, which is what buys the claim its extra room. Move one of those
       three and the other two have to move. */
    --t-hero2: clamp(2.9rem, min(5.82vw, 9.25vh), 4.3rem);
  }
  /* Real vertical command only where there is room for it. Never on a
     phone, where a min-height pushes the CTA under the fold. */
  @media (min-width: 1001px) {
    .hero2 { min-height: min(calc(100svh - 92px), 900px); }
  }

  .hero2__centre {
    position: relative;
    z-index: 2;
    /* 48rem held line two at the old 3.9rem cap and nothing larger: the
       line measures 11.0em, which is 755px once the type caps at 4.3rem,
       and a 48rem column less its two 24px pads leaves 720. 52rem leaves
       784, about 4% of slack, and stays under --claim-w so the photo
       columns are still the outer constraint rather than this one. */
    max-width: 52rem;
    /* Half the site gutter. The claim sets its own line breaks, so the
       column's padding is free to come in and tighten the block. Only above
       640px: see the phone override, where the claim wraps itself and needs
       the full gutter to keep its ink off the bezel. */
    padding-inline: calc(var(--gut) / 2);
    text-align: center;
  }
  /* Below 480px the h1's spans stop being blocks and the claim sets to the
     container rather than to its own hand-cut lines, so a half gutter put
     it hard against both edges of the screen. */
  @media (max-width: 639px) {
    .hero2__centre { padding-inline: var(--gut); }
  }
  /* Round 9: the message sits 5% of the hero's height above dead centre.
     Optical centring rather than geometric, which is the same reason a
     poster's type sits high: the scroll arrow and the long fall of the
     photo columns both weight the bottom half, so a mathematically centred
     claim reads low. The 5% is taken off the same expression .hero2 uses
     for its min-height, so the two cannot drift. Only where that
     min-height exists; below 1001px the hero is exactly as tall as its
     content and there is no slack to move within, only the header to run
     into. */
  @media (min-width: 1001px) {
    .hero2__centre { transform: translateY(calc(min(100svh - 92px, 900px) * -0.05)); }
  }

  /* The hinge, promoted. It used to sit under the claim and read "But with
     Vantical", turning a problem into a solution. The claim is a promise
     now, so there is no turn to make: the mark and the reader's own trade
     go first instead, and the promise lands on a reader who has already
     recognised themselves. */
  .hero2 .turn2 {
    /* Round 8, up about half again. This gap and the one above the button
       were both drawn when the sub-line sat between the claim and the CTA;
       taking that line out shortened the hero without giving the three
       pieces that remain any more air, so they ended up closer together
       than they had ever been. The vh term stays in the middle so a short
       laptop screen still tightens the stack rather than pushing the button
       towards the fold. */
    margin-bottom: clamp(2.6rem, 5.2vh, 3.6rem);
    display: flex;
    justify-content: center;
  }
  .hero2 .turn__badge {
    /* Size stays on --t-md, where the badge was drawn. Its new prominence
       comes from sitting first, not from being a pixel bigger.

       preview.css keeps "But with Vantical" on one line and gives the badge
       flex: none to do it. This line is three times as long, so it has to be
       allowed both to wrap and to shrink: white-space alone does nothing
       while the flex basis is still max-content. */
    flex: 0 1 auto;
    max-width: 100%;
    white-space: normal;
    text-wrap: balance;
    justify-content: center;
    font-size: var(--t-icp);
    letter-spacing: -0.014em;
  }
  .hero2 .turn__mark { width: 1.55em; height: 1.55em; }
  /* Once the line wraps, the badge is as wide as the column and the mark
     ends up marooned at the far left of a centred two-line label. Stack it
     instead, so both are centred and the pairing still reads. */
  @media (max-width: 640px) {
    .hero2 .turn__badge { flex-direction: column; gap: 0.3rem; }
  }

  /* The claim breaks in three fixed lines rather than wrapping, so the
     break is a decision rather than a consequence of the container width:
     "3 months." stays whole and the promise word stands alone. Below 480px
     line two cannot fit, so the spans go back to flowing and the h1 wraps
     itself. */
  .hero2__h1 {
    font-size: var(--t-hero2);
    /* 1.02 was drawn for a smaller claim, where three tight lines read as
       one block. At 4.3rem the same leading closes the lines up until the
       descenders of line one sit on the caps of line two. */
    line-height: 1.12;
    letter-spacing: -0.026em;
    /* Has to clear line two's own width, or the cap would break the line it
       exists to protect. 21ch rather than the old 20: the same 25
       characters, but two of them are digits now and a digit sets to a full
       ch where a lowercase letter does not. */
    max-width: 21ch;
    margin-inline: auto;
  }
  @media (min-width: 480px) {
    .hero2__h1 > span { display: block; }
  }
  /* The one word the claim turns on, in the brand's own blue. Blue You Read,
     so --mark-text rather than --mark; orange stays on the button. Block at
     every width, so it is alone on a phone too. */
  .hero2__vow { display: block; color: var(--mark-text); }

  /* The number the promise turns on, in the button's own orange. This
     breaks the rule the comment above states, that orange is the conversion
     action and nothing else, and it breaks it exactly once: the number and
     the button are halves of the same promise, and the claim is the one
     place on the page big enough to carry the colour. #E8481C is 3.8:1 on
     paper, which clears AA at this size and would not at any smaller one,
     so this stays scoped to the h1. Inline, not block: it is a nested span,
     so the > span rule above leaves it inside line one. */
  .hero2__num { color: var(--high); }

  /* Reopened in round 8, with the badge gap above and for the same reason.
     This number was measured with the sub-line sitting between the claim
     and the button; now it is the whole distance from one to the other, and
     it has to be the larger of the two gaps in the hero or the button
     drifts back towards the descenders on "Guaranteed." */
  .hero2__acts {
    margin-top: clamp(3.4rem, 6.6vh, 4.8rem);
    display: flex;
    justify-content: center;
  }
  /* The button grows with the block it closes. Scoped to the hero because
     .btn is shared and --t-ui is not ours alone. */
  .hero2 .btn--go { font-size: 1.2rem; padding: 0.94rem 1.62rem; }
  .hero2 .scroll { position: relative; z-index: 2; }
  /* Out of the grid flow entirely, so the message is the only thing being
     centred and the dead band under it closes. Only where the hero has a
     min-height to hang it from: on a phone the hero is exactly as tall as
     its content, so an absolute arrow would land on top of the last line. */
  @media (min-width: 1001px) {
    .hero2 .scroll {
      position: absolute;
      left: 50%;
      bottom: clamp(1.1rem, 3vh, 2rem);
      margin: 0;
      transform: translateX(-50%);
    }
  }

  /* ------------------------------------------------------------ rig ------
     The floating photos. Decorative, aria-hidden, pure CSS keyframes on
     transform and opacity: no JS loop, no scroll listener. The mask keeps
     cards clear of the very top and lets them dissolve before the fold.

     THE CYCLE. Everything here follows from one decision: the gap between
     two cards in a column is chosen, and the travel distance is derived
     from it, rather than the other way around.

       --gap-y   the space between one card and the next, chosen
       --travel  --gap-y x --n, so spacing IS --gap-y whatever the count
       --clear   --travel minus the rig's own height

     A card starts --clear above the rig and ends --travel below that, which
     puts its top exactly on the rig's bottom edge at 100%: fully gone
     before it restarts, so the loop is invisible. Because --travel does not
     depend on viewport height, one duration gives one constant speed on
     every screen, and --clear absorbs the difference. And because every
     card in a column takes part, all of the photographs cycle rather than
     the first few.

     No JavaScript is involved in any of it. */
  .rig2 {
    position: absolute;
    inset: 0;
    z-index: 1;
    overflow: clip;
    pointer-events: none;
    --hero-h: 100svh;
    --gap-y: calc(var(--card-h) + 5.5rem);
    /* The bottom fade runs long: a 384px card cut off in 40px reads as a
       crop, not a dissolve. */
    -webkit-mask-image: linear-gradient(to bottom,
      transparent 12px, #000 150px, #000 calc(100% - 130px), transparent 100%);
    mask-image: linear-gradient(to bottom,
      transparent 12px, #000 150px, #000 calc(100% - 130px), transparent 100%);
  }
  @media (min-width: 1001px) {
    .rig2 { --hero-h: min(100svh - 92px, 900px); }
  }
  .rig2__col {
    position: absolute;
    top: 0;
    bottom: 0;
    width: var(--card-w);
    --travel: calc(var(--gap-y) * var(--n));
    --clear: calc(var(--travel) - var(--hero-h));
  }
  .rig2__col--l { left: var(--rig-x); }
  .rig2__col--r { right: var(--rig-x); }
  /* Both photo sets sit in the column and only one shows, so each set gets
     its own element: :nth-child() has no by-class variant, and the card
     index has to count within a set rather than across both. */
  .rig2__set { position: absolute; inset: 0; }

  .card {
    position: absolute;
    top: calc(-1 * var(--clear));
    left: 0;
    width: 100%;
    opacity: 0;
    pointer-events: auto;
  }
  /* Index and tilt by position. Delay is derived from the index in the
     motion layer, so a treatment can change its count without a single
     number moving in the markup. */
  /* --ry only matters under reduced motion, where the field freezes into two
     cards a side. The two have to clear each other at the tallest card the
     rig ever draws, which is 418px at 1440. */
  .rig2__set .card:nth-child(1) { --i: 0; --rot: -1.6deg; --ry: 3svh; }
  .rig2__set .card:nth-child(2) { --i: 1; --rot: 1.2deg;  --ry: 55svh; }
  .rig2__set .card:nth-child(3) { --i: 2; --rot: -0.7deg; }
  .rig2__set .card:nth-child(4) { --i: 3; --rot: 1.8deg; }
  .rig2__set .card:nth-child(5) { --i: 4; --rot: -1.3deg; }
  .rig2__set .card:nth-child(6) { --i: 5; --rot: 0.9deg; }
  .rig2__col--r .card:nth-child(1) { --rot: 1.5deg;  --ry: 9svh; }
  .rig2__col--r .card:nth-child(2) { --rot: -1.1deg; --ry: 61svh; }
  .rig2__col--r .card:nth-child(3) { --rot: 0.6deg; }
  .rig2__col--r .card:nth-child(4) { --rot: -1.9deg; }
  .rig2__col--r .card:nth-child(5) { --rot: 1.4deg; }
  .rig2__col--r .card:nth-child(6) { --rot: -0.8deg; }

  .card__img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--r);
    box-shadow: 0 1px 2px rgb(18 20 23 / 0.1), 0 16px 36px rgb(18 20 23 / 0.14);
    transform: rotate(var(--rot, 0deg));
    transition: transform var(--t-move) var(--e-out),
                box-shadow var(--t-move) var(--e-out);
  }
  @media (hover: hover) and (pointer: fine) {
    /* Pausing mid-fade leaves the keyframe-driven opacity in charge, and
       animations beat normal author declarations, so the lift to full
       opacity needs the important flag. Deliberate, keep it. */
    .card:hover { animation-play-state: paused; opacity: 1 !important; }
    .card:hover .card__img {
      transform: rotate(var(--rot, 0deg)) translateY(-4px);
      box-shadow: 0 2px 4px rgb(18 20 23 / 0.12), 0 22px 48px rgb(18 20 23 / 0.2);
    }
  }

  /* --- the cards ----------------------------------------------------------
     5:6, not 3:4. The photographs worth showing are the real job shots and
     those are 520x390 landscape: a taller crop throws away the subject and
     upscales besides, where 5:6 keeps the frame and costs about 5%. Four a
     column each side, at different durations, so the two sides never pair
     up.

     Width is derived, not stepped. Line two of the claim is a fixed string
     at a known size, so the space left beside it is knowable: take half of
     what is left after the claim, less the column offset, less a 40px gap.
     342 is the ceiling, 10% down from the 380 of round 6. 380 was the point
     past which a 5:6 crop of a 520px source goes soft, so this stays inside
     that; it cannot go back up without the claim losing width again.
     --claim-w tracks the type: 11.0em of advance for those 25 characters,
     measured off the render at 1024 and 1440 rather than estimated, and the
     type caps at 4.3rem. 5.82vw x 11.0 is where the 64.0vw comes from, and
     4.3rem x 11.0 is the 757px. Both follow --t-hero2; if that moves again,
     recompute them rather than nudging them. The round 9 type rise is what
     the cards pay for: at 1440 a column comes down from about 297px to
     about 261px, still inside the 342 ceiling and well inside the point a
     5:6 crop of a 520px source goes soft. */
  .rig2 {
    /* The air between a card's inner edge and the first glyph of the claim.
       One name, used by both expressions below, because they have to agree:
       if they drift apart the columns stop tracking the message on a wide
       monitor. */
    --rig-gap: 68px;
    --claim-w: min(64.0vw, 757px);
    /* Two regimes, one expression. Below the width ceiling the offset is a
       plain clamp and the card absorbs whatever is left. Once the card pins
       at 380 the surplus has nowhere to go, so the offset takes it and the
       columns keep tracking the message instead of drifting back to the
       edges of a wide monitor. */
    --rig-x: min(
      9rem,
      max(
        clamp(0.4rem, 0.85vw, 1.15rem),
        calc((100vw - var(--claim-w)) / 2 - 342px - var(--rig-gap))
      )
    );
    --card-w: min(342px, calc((100vw - var(--claim-w)) / 2 - var(--rig-x) - var(--rig-gap)));
    --card-h: calc(var(--card-w) * 6 / 5);
  }
  .rig2__col--l { --dur: 300s; --n: 4; }
  .rig2__col--r { --dur: 258s; --n: 4; }
  .card__img { aspect-ratio: 5 / 6; object-fit: cover; }

  /* Only exists below 900px; the base rule keeps it out of the hero grid. */
  .hero2__scrim { display: none; }

  @media (max-width: 1000px) {
    /* Gutters gone: the photos sit well back behind a paper scrim so the
       message stays the loudest thing on the page.

       This used to start at 899px, which was right when the widest thing in
       the centre was a 16ch claim. The ICP line is 46 characters on one
       flex row and is wider than the claim between about 900 and 1000px:
       at 950 its ink reaches within a pixel of a card. Every other hero
       breakpoint is already 1001px, so this one joins them. */
    .rig2 { opacity: 0.5; }
    .rig2 .card { pointer-events: none; }
    .hero2__scrim {
      display: block;
      position: absolute;
      inset: 0;
      z-index: 1;
      background: radial-gradient(ellipse 90% 70% at 50% 45%,
        rgb(252 250 249 / 0.94) 0%, rgb(252 250 249 / 0.62) 70%, rgb(252 250 249 / 0.3) 100%);
    }
  }
  /* On a phone the photos are the hero's only image. Round 7 deleted the
     static strip that used to sit under the first viewport, so these carry
     it alone. The gutters are gone at this width so the cards sit behind
     the message: the same device the 640 to 1000 band uses, turned down
     further.

     --gap-y has to be its own value here. --clear is travel minus the rig
     height, and at this width the shared gap would give a travel barely
     longer than the viewport, leaving a card sitting on screen at phase
     zero and popping. This spaces the field so travel clears a full
     viewport plus a card. */
  @media (max-width: 639px) {
    /* 0.7, not the 0.5 the tablet band uses. The scrim is painted over the
       cards, so what survives is opacity x (1 - scrim alpha), and at the
       edges that is only about a third of the number set here. Below 0.7
       the photos stop reading as photographs and become pale rectangles. */
    .rig2 {
      opacity: 0.7;
      /* Round 7: in from the edge, from 0.25rem. About a tenth of the
         195px between edge and centre on a 390px screen, so the cards read
         as framing the message rather than clinging to the bezel. */
      --rig-x: 1.5rem;
      --card-w: 108px;
      --gap-y: calc(var(--card-h) + 10rem);
    }
    /* Pulled in from the edges so the outer sliver of each card sits in
       clearer air, while the centre band that carries the text keeps the
       full strength of the paper. */
    .hero2__scrim {
      background: radial-gradient(ellipse 76% 62% at 50% 44%,
        rgb(252 250 249 / 0.95) 0%, rgb(252 250 249 / 0.72) 68%, rgb(252 250 249 / 0.34) 100%);
    }
  }


  /* ------------------------------------------------------------ reel -----
     The promise, then the proof. This line spent round 7 as .hero2__sub,
     under the claim at --t-hero-sub, where it read as a caption on the
     claim rather than as the other half of the offer: everyone promises
     volume, nobody promises the follow up, so it is the differentiator and
     it earns a section. .band carries the vertical rhythm, exactly as #flow
     and #built do, so there is not one padding value written here. */
  .reel { text-align: center; }

  /* Two lines, broken at the second comma, and the break is a decision
     rather than a consequence of the container: the first two promises
     lead, the third lands on its own. It was three lines at its own larger
     step in round 7 and ran to four on a phone, which made the heading the
     object in this section and the film the footnote. It is the other way
     round now, so this is a lead-in and takes --t-h2-lg, the step the leaks
     title already runs at: the size the site uses for a heading that
     carries a section on its own. It is also as large as two lines can be
     here. Line one is 45 characters, Libre Franklin 700 averages about
     0.516em of advance, and 45 x 0.516 x 46px is already the whole 1084px
     content column.

     No max-width: the spans set the measure now, and any cap tight enough
     to be worth writing would wrap line one and undo the whole thing. */
  .reel__h {
    font-size: var(--t-h2-lg);
    /* The claim runs 1.12 because it is one sentence over three lines.
       These are two halves of a list, and at that leading they close into a
       block and stop reading as separate undertakings. */
    line-height: 1.22;
    letter-spacing: -0.02em;
    margin-inline: auto;
  }
  /* 800px, not the 640px this used to break at. Below 800 line one wants
     687px of a 736px column and loses that race immediately after, so the
     spans go back to flowing and the h2 wraps itself: two lines is a
     promise this can keep on a desktop and a tablet, not on a phone. */
  @media (min-width: 800px) {
    .reel__h > span { display: block; }
  }

  /* The film. It held a drawn placeholder until the real one landed; the
     border that framed it has gone with it, and the shadow .card__img
     carries is here instead, for the reason written there: an empty panel
     needs an edge, a picture of a person does not. --surface stays as the
     ground the poster paints over, so the frame is never a hole in the page
     on a slow connection.

     aspect-ratio does the whole responsive job, so this has no breakpoint
     and no width of its own: it fills .wrap, which caps it at 1084px, and
     at 16:9 that is 610px tall. It ran at 900px in round 7, a bespoke width
     chosen to match the heading. The film is the point of this section
     rather than an illustration under a title, so it takes the full content
     column instead and lines up with the flow steps, the build grid and the
     comparison table: the widest thing on the page, on the same grid as
     everything else. */
  .reel__frame {
    /* The same step .flow takes off its lede, reused rather than invented. */
    margin: clamp(2.25rem, 4vw, 3.25rem) auto 0;
    aspect-ratio: 16 / 9;
    display: grid;
    place-items: center;
    background: var(--surface);
    border-radius: var(--r);
    box-shadow: 0 1px 2px rgb(18 20 23 / 0.1), 0 16px 36px rgb(18 20 23 / 0.14);
    /* So the radius clips the player, not just the empty box. */
    overflow: hidden;
  }
  /* border: 0 for the same reason .book__slot iframe carries it. The film is
     16:9 and so is the frame, so cover crops nothing today; it is here so a
     recut at another ratio fills the frame instead of letterboxing it. */
  .reel__frame > video,
  .reel__frame > iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    object-fit: cover;
  }

  /* The calendar now sits directly under the film, and .leaks carries a
     margin-top of its own so its tinted full-bleed block gets air above it.
     That margin was invisible while .leaks followed a paper section: it was
     paper against paper. Against the calendar's dark ground it is an 88px
     stripe of paper trapped between two coloured blocks, which reads as a
     seam rather than as breathing room. Butt them instead: one hard edge,
     the same move the hero already makes into the calendar. */
  .close + .leaks { margin-top: 0; }

  /* ----------------------------------------------- prepare + privacy -----
     The quiet pages. Same world as the landing page, one reading measure,
     no photos. They are read once, in a hurry, usually straight after a
     booking, so the job here is calm: a column that sits in the middle of
     the screen instead of hugging its left edge, headings that separate
     sections without a rule doing it for them, and one list ornament per
     page rather than three across two. */
  /* The reading column ran at --measure, 62ch of 17px, which is about 525px
     inside a 1440px screen: 450px of empty paper each side. These pages are
     read once, in a hurry, by someone who is often outdoors, so the answer
     is a wider column and larger type rather than a cleverer layout.
     --measure stays where it is because index.html reads it. */
  .wrap--narrow {
    max-width: 880px;
    font-size: 1.125rem;
    --measure-quiet: 72ch;
  }

  /* Everything in the reading column is capped at the measure and centred
     as a block, so the page is balanced on a wide screen without the text
     itself being centred. The footer is included: a closing rule that
     overhangs the column it closes shares an edge with nothing and reads
     as a seam. */
  .wrap--narrow > * { max-width: var(--measure-quiet); margin-inline: auto; }
  /* @layer base caps every p at --measure. The block above already sets the
     column width, so the paragraphs inside it have to be let go or they
     keep setting at 62ch of 18px inside a 72ch box. */
  .wrap--narrow p { max-width: none; }

  /* Neither quiet page loads preview.js, so the masthead never gets the
     [data-stuck] edge it gets on the landing page. It is a logo on paper
     with nothing to reveal, so it takes the hairline permanently rather
     than sitting on content with no edge at all. */
  .masthead--quiet { border-block-end-color: var(--line); }

  .page-head {
    padding-top: clamp(3rem, 8vh, 5rem);
    /* The section below brings its own top padding, and two large gaps
       stacked read as a dropout rather than a break. */
    padding-bottom: 0;
  }
  .page-head h1 {
    font-size: var(--t-close);
    line-height: 1.08;
    letter-spacing: -0.022em;
    max-width: 18ch;
  }
  /* The one drawn accent on the quiet pages, in the brand's own blue.
     Orange stays reserved for the conversion action. */
  .page-head .u {
    font-style: normal;
    text-decoration: underline;
    text-decoration-color: var(--mark);
    text-decoration-thickness: 0.09em;
    text-underline-offset: 0.14em;
  }
  .page-head__lede {
    margin-top: 1.2rem;
    font-size: var(--t-lede);
    color: var(--ink-soft);
  }

  /* No rule on top of every section. Whitespace and a heading that is
     actually bigger than the body do the separating instead. */
  .sect { padding-block: clamp(2.5rem, 6vh, 4rem) 0; }
  .sect h2 {
    font-size: var(--t-quiet-h2);
    font-weight: 700;
    letter-spacing: -0.016em;
  }
  .sect > p:not(.eyebrow) { margin-top: 0.9rem; }
  .sect > p, .sect li { color: var(--ink); }

  /* Small blue wayfinding label, the same voice as the flow tags on the
     landing page. */
  .eyebrow {
    display: block;
    margin-bottom: 0.5rem;
    font-family: var(--f-display);
    font-weight: 600;
    font-size: var(--t-xs);
    color: var(--mark-text);
  }

  /* One structural rule on each quiet page, and it closes the reading, so
     the footer is not just another section. */
  .foot {
    margin-top: clamp(3rem, 7vh, 4.5rem);
    padding-block: 1.6rem clamp(1.75rem, 4vh, 2.5rem);
    border-top: 1px solid var(--line);
  }
  .foot .close__id dt { color: var(--ink-soft); }

  /* Checklist drawn like a job docket: an empty rule-off box per line. The
     one ornament prepare.html gets to keep, because a checklist of things
     to have ready is genuinely a docket. */
  /* One indent for both lists. They used to differ by 5px, which is enough
     to read as a wobble between two lists on the same page and not enough
     to read as anything on purpose. */
  .check { margin-top: 1.5rem; display: grid; gap: 1.35rem; }
  .check li, .agenda li { grid-template-columns: 1.6rem minmax(0, 1fr); gap: 0.7rem; }
  .check li { display: grid; }
  .check li::before {
    content: "";
    width: 1.15rem;
    height: 1.15rem;
    margin-top: 0.22rem;
    border: 1.5px solid var(--line-firm);
    border-radius: var(--r);
  }
  .check strong, .agenda strong { font-weight: 600; }

  .agenda { margin-top: 1.5rem; display: grid; gap: 1.35rem; counter-reset: item; }
  .agenda li { display: grid; counter-increment: item; }
  .agenda li::before {
    content: counter(item);
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-sm);
    color: var(--ink-soft);
    padding-top: 0.1rem;
  }

  /* Prose page (privacy). It ends on its own stamp rather than a contact
     footer, so it brings its own closing space. */
  .prose { padding-block-end: clamp(3rem, 8vh, 5rem); }
  .prose h2 {
    margin-top: clamp(2.5rem, 6vh, 3.75rem);
    font-size: var(--t-quiet-h2);
    letter-spacing: -0.016em;
  }
  .prose p { margin-top: 0.9rem; }
  /* No markers. Three identity lines do not need a list ornament, and
     dropping it leaves one ornament per quiet page. */
  .prose ul { margin-top: 0.9rem; display: grid; gap: 0.35rem; }
  .prose .stamp {
    margin-top: 1.75rem;
    font-size: var(--t-sm);
    color: var(--ink-soft);
  }

  @media (max-width: 560px) {
    .page-head h1 { max-width: none; }
    .foot .close__id { flex-direction: column; align-items: flex-start; gap: 0.6rem; }
  }

  /* ------------------------------------------------- the phone pass ------
     Round 7. These are overrides of components that live in preview.css,
     and they are here rather than there on purpose.

     The page list this comment used to give is out of date: new.html became
     index.html at cutover and brought its <link> to this file with it, so
     index.html now loads both sheets. The reason still stands, and it is
     booked.html that keeps it standing. That page loads preview.css alone,
     so preview.css is the shared sheet and anything written there is bytes
     and blast radius on a bare booking interstitial. hero2.css is loaded by
     the three pages that are actually the site.

     Same layer as preview.css's own responsive rules, and this file loads
     second, so source order wins. */

  /* The wide lede is the default and the narrow one is the exception, so
     this has to sit above the query: same specificity, and whichever comes
     last would otherwise win at every width. */
  .cmp__lede--narrow { display: none; }

  /* Out-specifies preview.css's .flow__step--you p, which is 0-2-1 and has
     been quietly repainting this line --ink at every width. The tag is the
     blue marker on the step he owns, drawn to match the heading rather than
     the body. Outside the query on purpose: fixed on a phone but still
     broken on a desktop would be worse than either. Since cutover index.html
     loads this file, so the fix reaches the live page too. */
  .flow__step--you .flow__tag { color: var(--mark-text); }

  @media (max-width: 560px) {
    /* Until now a phone got the desktop bar untouched: a 92px block with
       the lockup pinned at its 150px floor, because 15vw is only 58px at
       this width and the floor was doing all the work. The logo comes
       down, the CTA text goes up from 15px to 16px, and the bar loses the
       height it was not using. Roughly width neutral, but the button stops
       reading as an afterthought beside the lockup. */
    .masthead__inner { min-height: 76px; padding: 0.6rem var(--gut); }
    .lockup { width: clamp(132px, 34vw, 150px); }
    .masthead__cta { font-size: var(--t-ui); padding: 0.62rem 1.05rem; }
    /* Both offsets are measured off the bar above, so they move with it. */
    [id] { scroll-margin-top: 88px; }
    .anchor { scroll-margin-top: 104px; }

    /* --pad-y bottoms out at its 3.75rem floor on every phone, and
       preview.css then collapses the top padding of any paper band that
       follows another paper band, which is What actually gets built after
       How we fix it. On a wide screen those two reading as one continuous
       sheet is the intent. On a phone, where How we fix it is already a
       plain vertical stack, the second section just reads as more of the
       first. Give the padding back and draw the edge. */
    :root { --pad-y: 4.75rem; }
    .band:not(.band--tint) + .band:not(.band--tint) {
      padding-block-start: var(--pad-y);
      border-block-start: 1px solid var(--line);
    }

    /* One column strips out both cues at once: the four across reading and
       the connector between them. What was left was four identical ruled
       slabs, each with an orphaned grey digit above its heading. Put the
       number beside the text and let it carry the sequence instead. */
    .flow { gap: 1.6rem; }
    .flow__step {
      display: grid;
      grid-template-columns: auto 1fr;
      column-gap: 0.85rem;
      padding-block-start: 0.9rem;
    }
    .flow__n {
      grid-row: 1 / span 2;
      align-self: start;
      margin: 0;
      font-size: var(--t-h3);
      /* Stays --ink-soft. It is the only thing carrying the sequence now
         that the connector is gone, so it is content, not decoration. */
    }
    .flow__h, .flow__step p, .flow__tag { grid-column: 2; }

    /* 660px of table inside 390px of phone, with a 15rem sticky row label
       eating the first 240px of it, left about one and a half data columns
       visible and pushed our own column off screen first. Two columns fit
       with no scrolling at all, so the label stops being sticky and the
       swipe hint retires itself: setupCmpHint only unhides it when the
       table actually overflows. Columns are 1 label, 2 Vantical, 3 lead
       marketplace, then the two that go. */
    .cmp th:nth-child(n + 4), .cmp td:nth-child(n + 4) { display: none; }
    .cmp { min-width: 0; }
    /* Was painted --paper to cover the columns sliding under it, which put
       a paper stripe down a tinted band. Nothing slides now. */
    .cmp tbody th { min-width: 0; position: static; background: none; }
    .cmp th, .cmp td { padding: 0.85rem 0.6rem; }
    /* Left to itself the two tick columns take more than half the screen
       and every row label wraps to three lines. The label is the thing
       being read; the ticks only need to be findable by eye. */
    .cmp thead th:first-child, .cmp tbody th { width: 46%; }

    .cmp__lede--wide { display: none; }
    .cmp__lede--narrow { display: block; }
  }
}

/* ========================================================= TOKENS ========= */
@layer tokens {
  :root {
    /* The quiet pages used --t-h3, which tops out at 20.8px against 17px
       body: not a step, a stumble. This is a real one, and it is the only
       size the two pages needed that the landing page did not already have. */
    --t-quiet-h2: clamp(1.4rem, 2.1vw, 1.75rem);

    /* The line that says who the page is for, above the claim. A step up
       from --t-md, where the badge was drawn when it only had to carry two
       words. Named rather than inlined, per the convention preview.css sets
       for fluid display steps. The clamp is load bearing rather than
       decoration: at a flat 24px the line becomes wider than the claim and
       reaches a photo card around 1024px, where the claim itself does not. */
    --t-icp: clamp(1.32rem, 2.04vw, 1.8rem);

    /* The promise section's heading had its own step here in round 7,
       --t-reel at 2 to 3.25rem, sized to sit just under the claim. Round 8
       made the film the object in that section and the line a lead-in over
       it, and two lines of a 72 character sentence do not fit in the
       content column above about 46px anyway. It reads --t-h2-lg now, the
       step the leaks title already runs at, and the token is gone rather
       than left behind at a value nothing uses. */
  }
}

/* ========================================================= MOTION ========= */
@layer motion {
  /* The float. Linear, because it is constant ambient motion, not an
     entrance, and slow enough to read as drift rather than traffic.
     transform and opacity only. */
  @keyframes drift2 {
    0%   { transform: translate3d(0, 0, 0); opacity: 0; }
    8%   { opacity: 1; }
    88%  { opacity: 1; }
    100% { transform: translate3d(0, var(--travel), 0); opacity: 0; }
  }
  .card {
    animation: drift2 var(--dur, 150s) linear
               calc(-1 * var(--i, 0) * var(--dur, 150s) / var(--n, 5)) infinite;
  }

  @media (prefers-reduced-motion: reduce) {
    /* A still, staggered arrangement: two photos per side, placed by the
       per-card --ry. */
    .card {
      animation: none;
      opacity: 1;
      top: 0;
      transform: translate3d(0, var(--ry, 18svh), 0);
    }
    .rig2__set .card:nth-child(n + 3) { display: none; }
  }
}
