/* ==========================================================================
   Vantical, preview build, round 3

   Same layer discipline as site.css, so a later rule can never win by
   accident. Section padding lives only in `layout` and is never restated.
   Component responsive overrides stay in `@layer components`, never in
   `layout`, or they silently lose.
   ========================================================================== */
@layer reset, tokens, base, layout, components, motion, utilities;

/* ========================================================== RESET ========= */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; }
  body, h1, h2, h3, p, ul, ol, dl, dd, figure, fieldset { margin: 0; }
  ul, ol { padding: 0; list-style: none; }
  img, svg { display: block; max-width: 100%; }
  img { height: auto; }
  a { color: inherit; }
  table { border-collapse: collapse; }
  cite { font-style: normal; }
}

/* ========================================================= TOKENS ========= */
@layer tokens {
  :root {
    /* Palette. Every colour traces back to the logo: the warm arc is the
       accent, the cool arc marks our column, and the ink is the wordmark. */
    --paper:     #FCFAF9;  /* page ground */
    --tint:      #F4F0EA;  /* the alternate band. Warm, never inverted */
    --surface:   #EFEAE3;  /* panels */
    --line:      #E2DCD4;  /* hairline */
    --line-firm: #C6BDB2;  /* structural rule */
    --ink:       #121417;  /* logo spec */
    --ink-soft:  #55565A;  /* 7.0:1 on paper */

    /* The logo's cool arc. Marks our column in the comparison, and nothing
       else. It exists so the marked column never has to borrow the accent. */
    --mark:      #2E6BEB;
    --mark-tint: #EBEFF8;  /* --mark at 8% over paper */
    --mark-text: #1E51C4;  /* the same hue darkened until it clears AA */

    /* The closing section. Lifted off the #121417 the logo tile specs, which
       read as hard black across a full width band. Same hue family, so the
       mark still sits correctly on it. Every pairing re-checked. */
    --dark:       #1E2024;
    --dark-soft:  #A8ABB2;  /* 7.1:1 on dark */
    --dark-panel: #272A2F;
    --dark-edge:  #6E7178;  /* 3.2:1 on dark, clears a UI boundary */

    /* The conversion action, and nothing else. */
    --high:      #E8481C;
    --high-hi:   #F2551F;
    --high-edge: #B8360F;  /* the darker bottom edge, same hue */
    /* True black, not --ink. This is the pairing that carries the CTA:
       #000 on --high is 5.37:1, --ink on it is 4.76:1 and reads muddy.
       Named so it cannot drift back to --ink by accident. */
    --on-high:   #000000;

    /* Type. Libre Franklin is an American Gothic revival: newspaper mastheads
       and public signage. Source Sans 3 is a humanist text face drawn for
       screen reading. Neither is geometric, neither is condensed, and there is
       no mono anywhere on the page. */
    --f-display: 'Libre Franklin', system-ui, sans-serif;
    --f-body: 'Source Sans 3', system-ui, sans-serif;

    --t-hero: clamp(2.5rem, 4.6vw, 3.9rem);
    --t-h2:   clamp(1.6rem, 2.9vw, 2.25rem);
    --t-h3:   clamp(1.15rem, 1.4vw, 1.3rem);
    --t-lede: clamp(1.09rem, 1.4vw, 1.2rem);
    --t-md:   1.1875rem;  /* 19px */
    --t-body: 1.0625rem;  /* 17px. The reader is 35 to 60, outdoors, on a phone */
    --t-ui:   1rem;       /* 16px. Buttons, controls, secondary prose */
    --t-sm:   0.9375rem;  /* 15px */
    --t-xs:   0.8125rem;  /* 13px. Column subtitles and caption notes only */

    /* Fluid display steps, named rather than inlined as one-off clamps. */
    --t-sub:   clamp(1.06rem, 1.15vw, 1.18rem); /* hero subtext, beside the badge */
    --t-lead:  clamp(1.3rem, 1.8vw, 1.6rem);    /* the three jobs headings */
    --t-h2-lg: clamp(1.85rem, 3.4vw, 2.7rem);   /* the three jobs section title */
    --t-close: clamp(1.9rem, 4vw, 3.1rem);      /* the closing headline */
    --t-stmt:  clamp(1.15rem, 1.9vw, 1.45rem);  /* the closing statement */

    /* Rhythm */
    --pad-y: clamp(3.75rem, 7vw, 6.5rem);
    --gut: clamp(1.25rem, 4vw, 3rem);
    --max: 1180px;
    --max-hero: 1240px;  /* the hero alone runs slightly wider, so the photo can grow */
    --measure: 62ch;

    /* One radius. Surfaces and controls alike. */
    --r: 6px;

    /* Motion. Ease out for entrances. The hero crossfade is a dissolve, not
       an entrance, so it runs long and symmetrical. */
    --e-out: cubic-bezier(0.22, 0.8, 0.3, 1);
    --e-fade: cubic-bezier(0.4, 0, 0.2, 1);
    --t-press: 150ms;
    --t-move: 220ms;
    --t-fade: 1100ms;
    --t-dwell: 7000ms;
  }
}

/* =========================================================== BASE ========= */
@layer base {
  html { scroll-behavior: smooth; }
  @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

  body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--f-body);
    font-size: var(--t-body);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
  }

  h1, h2, h3 {
    font-family: var(--f-display);
    font-weight: 700;
    line-height: 1.12;
    letter-spacing: -0.014em;
    text-wrap: balance;
  }

  p { text-wrap: pretty; max-width: var(--measure); }
  p + p { margin-top: 0.85em; }
  b, strong { font-weight: 600; }

  a { text-underline-offset: 0.2em; text-decoration-thickness: from-font; }

  :focus-visible {
    outline: 3px solid var(--ink);
    outline-offset: 3px;
    border-radius: var(--r);
  }
  .close :focus-visible,
  .sign :focus-visible { outline-color: var(--paper); }

  ::selection { background: var(--ink); color: var(--paper); }
}

/* ========================================================= LAYOUT ========= */
@layer layout {
  .wrap {
    width: 100%;
    max-width: var(--max);
    margin-inline: auto;
    padding-inline: var(--gut);
  }

  /* Every section takes its vertical rhythm from here and nowhere else. */
  .band { padding-block: var(--pad-y); }
  .band--tint { background: var(--tint); }

  /* Two paper bands in a row read as one continuous sheet. Both sides have
     to be checked: matching only the second one zeroed the padding after the
     tint band too, which collapsed the gap above What actually gets built. */
  .band:not(.band--tint) + .band:not(.band--tint) { padding-block-start: 0; }

  .anchor { display: block; height: 0; scroll-margin-top: 120px; }
  [id] { scroll-margin-top: 104px; }
}

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

  /* ---------------------------------------------------------- skip link -- */
  .skip {
    position: fixed;
    top: 0; left: 50%;
    transform: translate(-50%, -110%);
    z-index: 60;
    background: var(--ink);
    color: var(--paper);
    padding: 0.7rem 1.2rem;
    font-family: var(--f-display);
    font-weight: 600;
    text-decoration: none;
    border-radius: 0 0 var(--r) var(--r);
  }
  .skip:focus-visible { transform: translate(-50%, 0); outline-offset: -3px; }

  /* --------------------------------------------------------- masthead ---- */
  .masthead {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgb(252 250 249 / 0.9);
    backdrop-filter: blur(10px);
    border-block-end: 1px solid transparent;
    transition: border-color var(--t-move) ease;
  }
  .masthead[data-stuck] { border-block-end-color: var(--line); }

  .masthead__inner {
    max-width: var(--max);
    margin-inline: auto;
    padding: 0.85rem var(--gut);
    min-height: 92px;
    display: flex;
    align-items: center;
    gap: clamp(1rem, 3vw, 2.5rem);
  }
  /* The lockup is the brand. It gets real size rather than being tucked into
     a corner at nav-link scale. */
  .masthead__logo { display: block; margin-inline-end: auto; }
  .lockup { width: clamp(150px, 15vw, 190px); height: auto; }

  .masthead__nav {
    display: flex;
    gap: clamp(1rem, 2vw, 1.9rem);
    font-family: var(--f-display);
    font-weight: 600;
    font-size: var(--t-sm);
  }
  .masthead__nav a {
    text-decoration: none;
    color: var(--ink-soft);
    padding-block: 0.3rem;
    border-block-end: 2px solid transparent;
    transition: color var(--t-press) ease, border-color var(--t-press) ease;
  }
  @media (hover: hover) and (pointer: fine) {
    .masthead__nav a:hover { color: var(--ink); border-block-end-color: var(--ink); }
  }

  /* ------------------------------------------------------------ buttons -- */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-ui);
    text-decoration: none;
    white-space: nowrap;
    border-radius: var(--r);
    transition: transform var(--t-press) var(--e-out),
                background-color var(--t-press) ease;
  }
  .btn:active { transform: scale(0.98); }

  /* True black on the brand orange is 5.37:1. #121417 on it was 4.76 and read
     muddy. The orange itself is untouched, and the darker bottom edge is the
     same hue, so the button gains depth without a gradient. */
  .btn--go {
    background: var(--high);
    color: var(--on-high);
    padding: 0.78rem 1.35rem;
    box-shadow: inset 0 -3px 0 var(--high-edge),
                0 1px 2px rgb(18 20 23 / 0.2);
  }
  @media (hover: hover) and (pointer: fine) {
    .btn--go:hover { background: var(--high-hi); }
  }

  .btn--quiet {
    color: var(--ink);
    padding: 0.78rem 0.2rem;
    font-weight: 600;
    border-block-end: 2px solid var(--line-firm);
    border-radius: 0;
  }
  @media (hover: hover) and (pointer: fine) {
    .btn--quiet:hover { border-block-end-color: var(--ink); }
  }

  .masthead__cta { padding: 0.68rem 1.2rem; font-size: var(--t-sm); }

  /* ---------------------------------------------------------------- hero -- */
  .hero { padding-block: clamp(1.25rem, 2.2vw, 2rem) 0; }
  .hero__inner {
    max-width: var(--max-hero);
    margin-inline: auto;
    padding-inline: var(--gut);
    display: grid;
    grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
    gap: clamp(1.75rem, 3vw, 2.75rem);
    align-items: center;
  }
  .hero__h1 {
    font-size: var(--t-hero);
    line-height: 1.04;
    letter-spacing: -0.024em;
    max-width: 15ch;
  }
  .hero__sub {
    margin-top: 1.3rem;
    font-size: var(--t-sub);
    line-height: 1.5;
    color: var(--ink-soft);
    max-width: 34ch;
  }
  /* The headline states the problem. This is the hinge: the mark and the
     name, then what changes, sitting beside it rather than under it. */
  .turn {
    margin-top: clamp(1.4rem, 2.2vw, 1.9rem);
    display: flex;
    align-items: flex-start;
    gap: clamp(0.9rem, 1.6vw, 1.4rem);
  }
  .turn__badge {
    flex: none;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-block-start: 0.15rem;
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-md);
    line-height: 1.3;
    letter-spacing: -0.012em;
    white-space: nowrap;  /* three lines of "But with Vantical" reads as a fault */
  }
  .turn__mark { flex: none; width: 2.1rem; height: 2.1rem; }
  .turn .hero__sub {
    margin-top: 0;
    padding-left: clamp(0.9rem, 1.6vw, 1.4rem);
    border-left: 2px solid var(--line-firm);
  }

  .hero__frame { display: flex; flex-direction: column; }
  .hero__pic img {
    width: 100%;
    border-radius: var(--r);
    box-shadow: 0 1px 2px rgb(18 20 23 / 0.1), 0 16px 36px rgb(18 20 23 / 0.12);
  }

  /* The three slides share one grid cell, so the block sizes to the tallest
     and nothing on the page moves when the slide changes. Without JS only the
     first slide exists, so they never stack on top of each other. */
  [data-rotate] { display: grid; }
  [data-rotate] > .slide { grid-area: 1 / 1; }
  .slide:not(.is-on) { display: none; }

  /* ----------------------------------------------------------- hero cue -- */
  /* One bar, filling across the dwell. It describes the carousel, so it sits
     under it and runs its full width rather than the text column's. */
  .cue { display: none; margin-top: 0.9rem; }
  .js .cue { display: block; }
  .cue__track {
    display: block;
    width: 100%;
    height: 4px;
    background: var(--line-firm);
    border-radius: var(--r);
    overflow: hidden;
  }
  .cue__track i {
    display: block;
    width: 100%; height: 100%;
    background: var(--ink);
    transform: scaleX(0);
    transform-origin: left center;
    will-change: transform;  /* keeps the fill on the compositor */
  }

  /* ------------------------------------------------------ scroll arrow --- */
  /* A real link to the next section rather than a decorative "scroll" label,
     so it works on click and by keyboard as well as reading as a hint. */
  .scroll {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.9rem; height: 2.9rem;
    margin: clamp(1.25rem, 2.4vw, 2rem) auto 0;
    border-radius: 50%;
    border: 1px solid var(--line-firm);
    color: var(--ink-soft);
    transition: color var(--t-press) ease, border-color var(--t-press) ease;
  }
  .scroll__ico {
    width: 1.3rem; height: 1.3rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  @media (hover: hover) and (pointer: fine) {
    .scroll:hover { color: var(--ink); border-color: var(--ink); }
  }

  /* ---------------------------------------------------------- headings --- */
  .h2 { font-size: var(--t-h2); max-width: 24ch; }
  .h3 { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.008em; }
  .lede {
    margin-top: 0.9rem;
    font-size: var(--t-lede);
    color: var(--ink-soft);
    max-width: 54ch;
  }

  /* ------------------------------------------------------------- leaks --- */
  /* Full bleed photo down one side. The text column is centred against it so
     the section does not end in a band of dead space. */
  .leaks {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    align-items: stretch;
    background: var(--tint);
    margin-top: clamp(3rem, 6vw, 5.5rem);
  }
  .leaks__pic img { width: 100%; height: 100%; object-fit: cover; }
  .kit__pic img { width: 100%; }
  /* This title carries the section on its own, so it runs a step above the
     other h2s rather than matching them. */
  .leaks__say .h2 { font-size: var(--t-h2-lg); max-width: 20ch; }
  .leaks__say {
    align-self: center;
    padding: clamp(2.75rem, 5.5vw, 4.5rem) var(--gut) clamp(2.75rem, 5.5vw, 4.5rem) clamp(2rem, 4vw, 3.5rem);
    max-width: 40rem;
  }

  .log { margin-top: clamp(1.75rem, 3vw, 2.5rem); }
  .log__row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: clamp(1.25rem, 2vw, 1.75rem);
    padding-block: clamp(1.5rem, 2.6vw, 2.1rem);
    border-block-start: 1px solid var(--line-firm);
  }
  .log__row:last-child { border-block-end: 1px solid var(--line-firm); }
  .log__row h3 { font-size: var(--t-lead); margin-bottom: 0.4rem; }
  .log__row p { color: var(--ink-soft); font-size: var(--t-lede); line-height: 1.55; }

  /* Tabler outline (MIT), inlined as real path data rather than drawn here.
     Struck in the logo's cool arc: the only colour on the page besides the
     button, and it is already the brand's own. */
  .ico {
    width: clamp(2.25rem, 3vw, 2.9rem);
    height: clamp(2.25rem, 3vw, 2.9rem);
    margin-top: 0.2rem;
    flex: none;
    fill: none;
    stroke: var(--mark-text);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  /* --------------------------------------------------------------- kit --- */
  /* What gets built. Six things, scannable, rather than two stacked lists.
     Rule topped cells, so it reads as a continuation of the steps above. */
  .kit__pic {
    margin-top: clamp(1.75rem, 3vw, 2.5rem);
    border-radius: var(--r);
    overflow: hidden;
  }
  .kit__pic img { width: 100%; }

  .kit {
    margin-top: clamp(2.25rem, 4vw, 3rem);
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(1.5rem, 2.75vw, 2.5rem) clamp(1.75rem, 3vw, 2.75rem);
  }
  .kit__item { border-block-start: 1px solid var(--line-firm); padding-block-start: 1rem; }
  /* Two icon families in one grid: Simple Icons (Meta, Instagram) are solid
     marks, Tabler are stroked. Same box and same colour so the row still
     reads as one set. */
  .kit__ico {
    width: 1.75rem; height: 1.75rem;
    margin-bottom: 0.7rem;
    fill: none;
    stroke: var(--mark-text);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* Meta and Instagram in a single flat colour, which both brands allow. Same
     colour as the stroked four, so the six read as one set. */
  .kit__ico--fill { fill: var(--mark-text); stroke: none; }
  .kit__h {
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-md);
    letter-spacing: -0.01em;
    margin-bottom: 0.35rem;
  }
  .kit__item p { color: var(--ink-soft); font-size: var(--t-ui); }

  /* -------------------------------------------------------------- flow --- */
  /* Four steps, left to right, joined by a connector so it reads as one
     movement rather than four cards. The fourth is his, and it is marked in
     the brand blue and given a heavier rule so the handover is obvious. */
  .flow {
    margin-top: clamp(2.25rem, 4vw, 3.25rem);
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: clamp(1.25rem, 2.5vw, 2.25rem);
  }
  .flow__step {
    position: relative;
    border-block-start: 2px solid var(--line-firm);
    padding-block-start: 1.15rem;
  }
  /* The connector. Sits on the top rule, points at the next step, and is
     suppressed on the last one and whenever the row wraps. */
  .flow__step::after {
    content: '';
    position: absolute;
    top: -5px;
    right: calc(clamp(1.25rem, 2.5vw, 2.25rem) * -0.5 - 4px);
    width: 8px; height: 8px;
    border-top: 2px solid var(--line-firm);
    border-right: 2px solid var(--line-firm);
    transform: rotate(45deg);
  }
  .flow__step:last-child::after { content: none; }

  .flow__n {
    display: block;
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-sm);
    color: var(--ink-soft);
    margin-bottom: 0.5rem;
  }
  .flow__h {
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-md);
    letter-spacing: -0.01em;
    margin-bottom: 0.4rem;
  }
  .flow__step p { color: var(--ink-soft); font-size: var(--t-ui); }

  /* The one he owns. */
  .flow__step--you { border-block-start-color: var(--mark); border-block-start-width: 4px; }
  .flow__step--you .flow__n,
  .flow__step--you .flow__h { color: var(--mark-text); }
  .flow__step--you p { color: var(--ink); }
  .flow__tag {
    margin-top: 0.85rem;
    font-family: var(--f-display);
    font-weight: 600;
    font-size: var(--t-xs);
    color: var(--mark-text);
  }

  /* ----------------------------------------------------------- compare --- */
  .cmp__scroll {
    margin-top: clamp(2rem, 3.5vw, 2.75rem);
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }
  .cmp { width: 100%; min-width: 660px; }
  .cmp th, .cmp td {
    padding: 1rem 0.85rem;
    border-block-end: 1px solid var(--line);
    vertical-align: top;
  }
  .cmp thead th {
    font-family: var(--f-display);
    font-weight: 600;
    font-size: var(--t-sm);
    text-align: center;
    line-height: 1.25;
    color: var(--ink-soft);  /* the competitor columns sit back */
    border-block-end: 2px solid var(--line-firm);
    vertical-align: bottom;
  }
  .cmp thead th small {
    display: block;
    margin-top: 0.3rem;
    font-family: var(--f-body);
    font-weight: 400;
    font-size: var(--t-xs);
    color: var(--ink-soft);
  }
  .cmp tbody th {
    text-align: left;
    font-family: var(--f-body);
    font-weight: 400;
    font-size: var(--t-ui);
    color: var(--ink);
    min-width: 15rem;
    background: var(--paper);
    position: sticky;
    left: 0;
  }
  .cmp td { text-align: center; }

  /* Our column is marked with the logo's cool arc, never with the accent.
     Orange on this page means press this, and a table column is not a
     button. The blue is already in the mark, so it still reads as ours. */
  .cmp__us { background: var(--mark-tint); }
  .cmp__mark { width: 1.85rem; height: 1.85rem; margin: 0 auto 0.45rem; }
  .cmp thead .cmp__us {
    font-weight: 800;
    font-size: var(--t-ui);
    color: var(--mark-text);
    border-block-end-color: var(--mark);
    border-block-start: 4px solid var(--mark);
    border-radius: var(--r) var(--r) 0 0;
  }
  .cmp tbody tr:last-child .cmp__us { border-radius: 0 0 var(--r) var(--r); }

  /* Marks are drawn here so they inherit currentColor. Every cell also
     carries a visually hidden Yes or No for a screen reader. */
  .cmp td::before {
    content: '';
    display: inline-block;
    width: 1.05rem; height: 1.05rem;
    background: currentColor;
    -webkit-mask: var(--m) center / contain no-repeat;
    mask: var(--m) center / contain no-repeat;
  }
  .cmp td.cmp__us::before { width: 1.35rem; height: 1.35rem; }
  .cmp td[data-v="yes"] {
    color: var(--ink);
    --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5 L6.2 12.2 L13.5 4.2' fill='none' stroke='black' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E");
  }
  .cmp td.cmp__us[data-v="yes"] { color: var(--mark-text); }
  /* The cross carries meaning, so it has to clear 3:1 as non-text content.
     line-firm was 1.78:1 and failed. */
  .cmp td[data-v="no"] {
    color: var(--ink-soft);
    --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 3.5 L12.5 12.5 M12.5 3.5 L3.5 12.5' fill='none' stroke='black' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E");
  }
  .cmp__hint { margin-top: 0.85rem; font-size: var(--t-sm); color: var(--ink-soft); }

  /* ------------------------------------------------------------- close --- */
  /* The booking band, second on the page, and the footer that closes it
     share this ground: two inversions that bracket the read instead of one
     that interrupts it. #121417 rather than navy, because logo-assets/README
     specs the dark mark against this exact ground, so the lockup in the
     footer sits on spec instead of fighting a blue field. */
  .close {
    background: var(--dark);
    color: var(--paper);
    padding-block: var(--pad-y);
    text-align: center;
  }
  /* The ask sits alone above the calendar, centred on it. It used to run
     beside the lockup; up here the calendar is the widest thing in the
     section and a heading offset to one side of it just looks adrift. */
  .book__ask { max-width: 46ch; margin-inline: auto; }
  .close__h {
    font-family: var(--f-display);
    font-weight: 700;
    font-size: var(--t-close);
    line-height: 1.05;
    letter-spacing: -0.022em;
  }
  .close__say {
    margin-top: 0.7rem;
    margin-inline: auto;
    font-size: var(--t-stmt);
    line-height: 1.35;
    color: var(--dark-soft);
    max-width: 32ch;
  }

  /* Sized here rather than by LeadConnector's form_embed.js. That script is
     the parent half of iframe-resizer, and it parks the frame at
     left:-9999px with opacity 0 while it waits for the child to report in.
     Verified still hidden 16s after load, so it is not used. The height
     below fits the whole widget: header, month grid and the slot list. */
  /* The widget carries a band of its own white padding at the top, and only
     paints about 705px of content into whatever height it is given, leaving
     dead space below. Measured, not guessed: rendered at full height, the
     content ended 705px down and 375px of empty ground followed.

     Tested rather than assumed: at 800px the widget renders the identical
     two column layout, so height does not drive that, width does. Sizing the
     frame to fit is therefore safer than leaving it tall and hiding the
     surplus, because hidden surplus could contain bookable slots on a busier
     day. At this height a longer list scrolls inside the frame instead. Only
     the widget's own top padding is cropped. */
  .book__slot {
    --crop-top: 56px;
    --crop-bot: 4px;
    margin-top: clamp(2.5rem, 5vw, 3.5rem);
    margin-inline: auto;
    max-width: 1100px;
    background: var(--paper);
    border-radius: var(--r);
    overflow: hidden;
  }
  .book__slot iframe {
    display: block;
    width: 100%;
    height: 800px;
    margin-top: calc(var(--crop-top) * -1);
    margin-bottom: calc(var(--crop-bot) * -1);
    border: 0;
  }

  /* ------------------------------------------------------------- sign --- */
  /* The sign-off: mark on the left, the four facts on the right, on the same
     ground as the booking band. NOT called .foot, which hero2.css already
     owns for the light footer on prepare.html and would half-restyle this
     one into unreadable dark-on-dark.

     Shallower than a band on purpose: it carries a mark and four facts, and
     full section padding around that much reads as a section with nothing
     in it. */
  .sign {
    background: var(--dark);
    color: var(--paper);
    padding-block: clamp(2.25rem, 4vw, 3.25rem);
  }
  .sign__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1.25rem clamp(1.75rem, 4vw, 3.5rem);
  }
  /* Smaller than it was above the calendar. Down here it is a signature,
     not an introduction. */
  .sign__lockup { flex: none; width: clamp(150px, 16vw, 210px); height: auto; }

  /* One flat line: label and value side by side, the items spread across
     the row. Wraps to a column only when there is genuinely no room.
     Shared with prepare.html, so the base stays centred and only the
     sign-off pushes it to the end of its row. */
  .close__id {
    display: flex;
    justify-content: center;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.6rem clamp(1.75rem, 4vw, 3.5rem);
    font-size: var(--t-sm);
  }
  .sign .close__id { justify-content: flex-end; gap: 0.6rem clamp(1.5rem, 3vw, 2.75rem); }
  .close__id > div { display: flex; align-items: baseline; gap: 0.55rem; }
  .close__id dt { color: var(--dark-soft); }
  .close__id a { text-decoration-thickness: 1px; }

  /* ==================================================== RESPONSIVE ======= */
  /* These live in `components` on purpose. In `layout` they would lose to
     the component rules above regardless of specificity, and every collapse
     on the page would silently stop working. */

  /* The hero gets real vertical command at desktop, where there is room for
     it. Never on a phone, where a min-height only pushes the CTA under the
     fold. */
  @media (min-width: 1001px) {
    .hero__inner {
      min-height: min(62vh, 600px);
      align-content: center;
      align-items: stretch;  /* the photo holds the column rather than floating in it */
    }
    .hero__pic { flex: 1; min-height: 0; }
    .hero__pic img { height: 100%; object-fit: cover; }
  }

  @media (max-width: 1000px) {
    .hero__inner { grid-template-columns: minmax(0, 1fr); gap: 2.25rem; }
    .hero__h1 { max-width: 17ch; }
    .leaks { grid-template-columns: minmax(0, 1fr); }
    .leaks__pic img { max-height: 340px; }
    .leaks__say { padding: clamp(2.25rem, 6vw, 3rem) var(--gut); max-width: none; }
  }

  @media (max-width: 860px) {
    .masthead__nav { display: none; }
    .kit { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .flow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .flow__step:nth-child(2)::after { content: none; }
  }

  @media (max-width: 560px) {
    .h2 { max-width: none; }
    .turn { flex-direction: column; gap: 0.7rem; }
    .turn__badge { white-space: normal; }
    /* Stacked, so the message gets the full column rather than the narrow
       measure it needs when it sits beside the badge. */
    .turn .hero__sub { padding-left: 0; border-left: 0; max-width: none; }
    .sign__inner { flex-direction: column; text-align: center; gap: 1.5rem; }
    .sign .close__id { justify-content: center; }
    /* The email runs nearly edge to edge at 390px, so the contact row steps
       down a size rather than risking an overflow on a narrower phone. */
    .kit, .flow { grid-template-columns: minmax(0, 1fr); }
    /* Stacked, so the connector would point sideways into nothing. */
    .flow__step::after { content: none; }
    /* Stacked on a phone: the calendar sits above the slot list, so the
       widget runs taller than the desktop layout and taller again once a
       date is tapped and the list appears. A fixed height cannot be right
       for both states, and being short by either costs a second scrollbar
       inside the first.

       setupBookHeight() in preview.js listens for the height the widget
       posts about itself and grows the frame to it, below this same 560px
       query. These two numbers are one decision in two files: move the
       query here and it has to move there.

       WHY THIS IS 1400 AND NOT THE REPORTED 936. The widget posts its
       height exactly once, on load, for the screen it loads with. It does
       not post again when a date is tapped and the slot list replaces the
       calendar, or when a time is tapped and the booking form replaces
       that. Tested by driving all three: one message, ever. So the report
       sizes the frame to the first screen and the last screen, which is the
       tallest, ends up scrolling inside it with the Schedule button below
       the fold. The listener cannot fix what it is never told.

       1400 is measured, not picked. The form's own fields run 657px in the
       widget's desktop layout, and on a phone they stack under a session
       card of about 300px with the button and padding under that: call it
       1100. The slot list, the other tall screen, measured 923px on a
       weekday with nine slots and grows with the list. 1400 clears both
       with room for a busier day.

       The cost is white space below the shorter screens, since the widget
       paints its own ground across whatever height it is given. That is the
       trade: a bit of empty panel on the calendar against a Schedule button
       nobody can find. If the empty band ever matters more than it does
       now, the fix is to start at the reported height and grow to this one
       when focus first enters the frame, which is the only cross-origin
       signal that the visitor has begun.

       NO TOP CROP HERE. It was 32px, to hide the band of white padding the
       widget paints above its calendar. The widget has three views and only
       one of them has that band: on the slot list the top 32px is the back
       arrow and the day, and the crop was cutting "Wednesday" in half on a
       real phone. A fixed crop cannot be right for all three views, and
       zero is the only value that can never eat content. The padding shows
       instead, which reads as part of the panel.

       --crop-bot is doing a different job now and stays. The frame is sized
       to the reported height plus both crops, so the 4px is slack the
       wrapper clips: room for the widget to round its own height down
       without opening a scrollbar inside the frame. */
    .book__slot { --crop-top: 0px; --crop-bot: 4px; }
    .book__slot iframe { height: 1400px; }
  }
}

/* ========================================================= MOTION ========= */
@layer motion {
  /* Hero crossfade. Opacity only, on a 7 second dwell driven from JS. The
     fade runs long and symmetrical so it dissolves rather than snaps.
     visibility leaves on a delay so the outgoing slide stays paintable for
     the length of the fade, then drops out of the accessibility tree. */
  .js [data-rotate] > .slide {
    display: block;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t-fade) var(--e-fade),
                visibility 0s linear var(--t-fade);
  }
  .js [data-rotate] > .slide.is-on {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--t-fade) var(--e-fade), visibility 0s;
  }

  /* The cue bar fills across the dwell. transform only, linear, so the rate
     matches the clock it is reporting. */
  .js .cue.is-running i { animation: cue-fill var(--t-dwell) linear forwards; }
  .js [data-hero][data-paused] .cue i { animation-play-state: paused; }
  @keyframes cue-fill {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }

  /* A slow bob on the arrow. transform only, and it stops on hover or focus
     so it is never moving while someone is trying to hit it. */
  .scroll__ico { animation: bob 1.9s ease-in-out infinite; }
  .scroll:hover .scroll__ico,
  .scroll:focus-visible .scroll__ico { animation-play-state: paused; }
  @keyframes bob {
    0%, 100% { transform: translateY(-3px); }
    50%      { transform: translateY(3px); }
  }

  /* Section level groups only. Fires once, never replays on scroll back. */
  .js [data-rv] {
    opacity: 0;
    transform: translateY(10px);
  }
  .js [data-rv].is-in {
    opacity: 1;
    transform: none;
    transition: opacity var(--t-move) var(--e-out),
                transform var(--t-move) var(--e-out);
    transition-delay: var(--rv-delay, 0ms);
  }

  @media (prefers-reduced-motion: reduce) {
    /* The rotation is halted in JS as well. This makes the first slide the
       only one that renders, rather than leaving three stacked. The cue is
       hidden outright: there is nothing to indicate when nothing rotates. */
    .js [data-rotate] > .slide { transition: none; }
    .js [data-rotate] > .slide:not(.is-on) { display: none; }
    .js .cue { display: none; }
    .scroll__ico { animation: none; }

    .js [data-rv] { opacity: 1; transform: none; }
    .js [data-rv].is-in { transition: none; }
    .btn, .masthead, .masthead__nav a { transition: none; }
    *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; }
  }
}

/* ====================================================== UTILITIES ========= */
@layer utilities {
  .vh {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
