/* Hallmark · shape: Split Studio (draw 9a8ff4) · genre: modern-minimal · theme: Console (deal 2/3 · seed petrol-pump-operations-app-46b8·734d4f55·2026-10-29·r0) · job: book · redesign: full · copy: verbatim (the hero headline is the brief's own chosen wording)
 * hero: Index · nav: floating pill · footer: mast · imagery: the product · signature: the owner's screen settling out of a tilt, then run through its window by the page's scroll · console: graphite, accent gold #D2A24C
 * axes: dark/grotesk-sans/chromatic-amber · posture: restrained · contrast: pass (lowest text pair 5.2:1, a dimmed step's sentence at 0.64 strength; the owner's messages, ink on their soft gold 12.3:1 and the times 5.5:1 at 14px; muted on paper 7.4:1; gold on paper 8.2:1; dark ink on gold 8.1:1; axe 0 violations at rest, motion on and off) · fold: pass (1280 x 800: head, lead, status line, button and the owner's alerts and figures, and all three alerts still at 1280 x 720 and 1366 x 768; the hero ends above the fold at 1440 x 900 and 1920 x 1080) · v2.0.0 */
/* Hallmark · pre-emit critique: P4 H4 E4 S4 R4 V4 · weakest: H, the page has five scroll set pieces (the hero's runway, the problem's pinned chapter, the tour's still phone, the panels, the close) and the squint test could read them as one rhythm; the problem pins on paper-2 and the tour sits on paper, so heavy and light still alternate */
/* Hallmark · waive 84 · capturing the live app would show real pump data, so the owner's screen is built on invented values · the screen holds invented sample figures and says so in its chip */
/* Hallmark · dismissed 40 · the board's text sits on the app's own light surfaces drawn inside the panel, never on the panel's paper-2 ground */
/* Hallmark · answered F1 · the visible words are compared with the draft words, which are typed with straight apostrophes; the merge of the new words sets them */
/* Hallmark · waive 44c · hero posture Index (stamped above): the head sits small over the owner's screen, which is the lead, so the picture's centre is far under the text block's · the first screen leads with the owner's screen, the strongest real thing the page has, and the head is the one line above it */
/* Hallmark · dismissed 58 · the busiest 900px window holds the four feature panels (a head and one sentence each, set as a grid of four) and the close's one line and button, which sit close together at the foot of the page */
/* Hallmark · dismissed 23 · .spine i and .tour-rail i fill a 2px page rule and a 2px rail, so the accent is a hairline and not a viewport-scale area */
/* Hallmark · dropped /compare.html · the six-colour theme switcher and its compare page were demo-only */
/* Hallmark · reworded the headings and lines to the new words */
/* Hallmark · answered F8 · the brief asks for scroll-triggered motion and animation runways, so more than one scroll pattern runs: the hero's pinned runway, the problem's pinned chapter, the tour's still phone, the progress spine and the close's clip wipe; the Floor holds (transform, opacity and clip-path only, a plain version under reduce motion, every word visible without script) */
/* Hallmark · answered: a load intro of about 1.8 s, asked for in the brief (the V's right arm starts at the far end of the name and sweeps back with the left arm to lock into the V, the gold bars glow, the name wipes out, then the logo floats into the header and takes its place); skippable, never under reduced motion, left out when the page starts slowly (after 0.9 s of styles or 1.2 s of scripts), CSS fallback at 2.4 s */
/* Hallmark · dismissed 49 · the footer's address is one line at every ordinary size and breaks only on a screen too narrow to hold it (a 200% zoom), because a cut-off address is worse than a broken one */
/* Hallmark · answered 29 (a glow on a dark ground): the intro's gold glow is asked for in the brief, intro only */
/* Hallmark · answered F8 · the problem is the owner's messages to his manager, sent one by one as the scroll passes them (the same pinned chapter, one pattern); the phone tour pushes its screens right to left */
@import url("./tokens.css");
@import url("./base.css");

/* ---- page ---- */
html { -webkit-text-size-adjust: 100%; font-synthesis: none; }
main { display: block; }
p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }

/* ---- logo and wordmark: Concept A, frame and pillars in the text colour, inner bars in gold ---- */
.lg-a { fill: var(--color-accent); }
.wordmark { font-family: var(--font-wordmark); font-weight: 800; font-synthesis: none; letter-spacing: -0.01em; line-height: 1; }

/* ---- buttons: Console's pair. The one filled primary (gold fill, dark ink) and the outlined control (paper-2, a 1px second rule), sentence case. A button is one line at every ordinary size and wraps, centred and balanced, only when the screen or the text size leaves it no room (200% zoom, a larger system font): nothing is ever cut off ---- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-xs); min-height: 52px; max-width: 100%; padding: var(--space-xs) var(--space-lg); border: var(--rule-hair) solid var(--color-accent); border-radius: var(--radius-pill); background: var(--color-accent); color: var(--color-accent-ink); font: 500 var(--text-md)/1.25 var(--font-body); text-align: center; text-wrap: balance; white-space: normal; text-decoration: none; cursor: pointer; transition: background-color var(--dur-short) var(--ease-out), border-color var(--dur-short) var(--ease-out), transform var(--dur-micro) var(--ease-out); }
.btn:hover { background: color-mix(in oklab, var(--color-accent) 84%, var(--color-ink)); border-color: color-mix(in oklab, var(--color-accent) 84%, var(--color-ink)); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }
.btn svg { flex: none; }
.btn--out { border-color: var(--color-rule-2); background: var(--color-paper-2); color: var(--color-ink); }
.btn--out:hover { border-color: var(--color-ink-2); background: var(--color-paper-3); }

/* text links in the chrome: underlined in the second rule colour, gold on hover */
.nav-link { display: inline-flex; align-items: center; min-height: 48px; padding: 0 var(--space-sm); text-align: center; overflow-wrap: break-word; color: var(--color-ink-2); font-size: var(--text-md); font-weight: 500; text-decoration-line: underline; text-decoration-color: var(--color-rule-2); text-underline-offset: 0.3em; transition: color var(--dur-micro) var(--ease-out), text-decoration-color var(--dur-micro) var(--ease-out); }
.nav-link:hover { color: var(--color-accent); text-decoration-color: currentColor; }
.nav-link:active { transform: translateY(1px); }

/* ---- nav: a floating pill, sticky, inside the capped container ---- */
.site-header { position: sticky; top: 0; z-index: var(--z-sticky-nav); } /* stuck, the pill sits one space-sm down */
.site-header > .container { padding-top: var(--space-sm); pointer-events: none; } /* only the pill takes the pointer, not the gap around it */
/* phones and tablets: the page ground behind the floating pill, from the top edge to the pill's lower edge and a short fade below it, so scrolled text never shows in the strip above the pill or in the gutters beside it
   (the tour's band has the same paper strip, .tour-side::before). The pill itself keeps its own lighter ground and border, so it still floats. */
@media (max-width: 59.99rem) {
  .site-header::before { content: ""; position: absolute; inset: 0 0 calc(-1 * var(--space-sm)); z-index: -1; background: linear-gradient(var(--color-paper) calc(100% - var(--space-sm)), transparent); pointer-events: none; }
}
.pill { pointer-events: auto; display: flex; align-items: center; justify-content: space-between; gap: 0 var(--space-md); flex-wrap: wrap; min-height: 64px; padding: var(--space-xs) var(--space-sm) var(--space-xs) var(--space-md); border: var(--rule-hair) solid var(--color-rule); border-radius: var(--radius-card); background: var(--color-paper-2); }
/* the brand's mark, gap and name in px, as plain numbers: the intro's lockup is the same numbers times --lu, so its flight onto the brand is one uniform scale at every width */
:root { --bm: 28; --bg: 12; --bw: 20; }
.brand { display: inline-flex; align-items: center; gap: calc(var(--bg) * 1px); min-width: 0; min-height: 48px; color: var(--color-ink); text-decoration: none; }
.brand svg { width: calc(var(--bm) * 1px); height: calc(var(--bm) * 1px); flex: none; }
.brand .wordmark { font-size: calc(var(--bw) * 1px); }
.pill-end { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0 var(--space-xs); min-width: 0; }
.pill-end .btn { display: none; }

/* ---- progress spine: a 2px rule at the left edge, its gold fill following the page's scroll (laptops; js/site.js) ---- */
.spine { display: none; }
.spine i { position: absolute; inset: 0; background: var(--color-accent); transform: scaleY(0); transform-origin: 50% 0; }

/* ---- hero: the Index posture. A small head above, the owner's screen as the lead under it, in a window that ends with the first screen ---- */
.hero { padding-block: var(--space-xl) var(--space-3xl); }
.opener { display: grid; gap: var(--space-lg); align-items: start; margin-bottom: var(--space-xl); }
.hero h1 { max-width: none; font-size: clamp(2.25rem, 2.6vw + 1rem, 3.25rem); line-height: 1.04; }
.opener-act { display: grid; gap: var(--space-md); justify-items: start; min-width: 0; }
.opener-cta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm) var(--space-lg); }
/* the proof line: body size and the second ink, read after what PumpVero is and before the ask (never above the headline, so it is no eyebrow) */
.status { color: var(--color-ink-2); font-size: var(--text-md); font-weight: 500; line-height: 1.5; }
.lead { max-width: 52ch; color: var(--color-ink-2); font-size: var(--text-md); line-height: 1.5; }
.hero-visual { min-width: 0; }

/* below 64rem a phone stands in for the owner's screen (css/tour.css dresses it) */
.tour-phone.hero-phone { margin: 0 auto; }
.ovb { display: none; }

/* ---- sections between the hero and the footer ---- */
.section { padding-block: var(--space-2xl); }
.head { display: flex; flex-direction: column; gap: var(--space-md); max-width: 760px; }
.sub { max-width: 52ch; font-size: var(--text-md); color: var(--color-ink-2); }

/* a split: text on one side, the proof on the other, the proof keeping the right side; stacked in reading order below 48rem */
.split { display: grid; gap: var(--space-xl) var(--gap-columns); align-items: center; }

/* problem: a band. The owner's own messages to his manager, set as a thread: right-aligned bubbles on the gold soft, each with a 1px gold edge (gold means a person), the times in mono under the words.
   On a laptop it is a pinned chapter (js/site.js): the first message is there, the scroll sends the other three one by one and, last, brings in the payoff line at the foot of the left column. Without script or under "reduce motion" it is this finished layout. */
.problem { background: var(--color-paper-2); border-block: var(--rule-hair) solid var(--color-rule); padding-block: var(--space-3xl); }
.problem h2 { max-width: 15ch; }
/* the payoff: a second display line, in full ink. On a laptop it sits at the foot of the left column, under the heading, so the heading and the line bracket the thread; on a phone it follows the thread */
.problem-line { max-width: 16ch; margin-top: var(--space-md); color: var(--color-ink); font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--tracking-display); line-height: 1.15; text-wrap: balance; }
.problem .split { row-gap: var(--space-lg); }
.thread { justify-self: end; width: 100%; max-width: 28rem; } /* the thread keeps the right side, its bubbles flush to the page's right edge */
.thread-who { padding-bottom: var(--space-sm); border-bottom: var(--rule-hair) solid var(--color-rule-2); color: var(--color-ink-2); font-size: var(--text-sm); font-weight: 500; line-height: 1.4; }
.thread-msgs { display: grid; justify-items: end; gap: var(--space-md); padding-top: var(--space-lg); } /* no reply is shown: the payoff line says who hears last */
.thread-msgs li { display: grid; gap: var(--space-2xs); max-width: 92%; padding: var(--space-sm) var(--space-md); border: var(--rule-hair) solid var(--color-accent); border-radius: var(--radius-card); background: var(--color-accent-soft); color: var(--color-ink); font-size: var(--text-xl); line-height: 1.25; overflow-wrap: break-word; }
.thread-msgs li:last-child { margin-top: var(--space-md); } /* the night, in the gap before the 7:05 am message: twice the others */
.thread-msgs time { justify-self: end; color: var(--color-muted); font: 400 var(--text-sm)/1.3 var(--font-outlier); font-variant-numeric: tabular-nums; }

/* the feature lines (inside the tour section, after the steps): one surface cut into four panels by 1px seams */
.panels { display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; border: var(--rule-hair) solid var(--color-rule); border-radius: var(--radius-card); background: var(--color-paper-2); color: var(--color-ink); }
.panels li { position: relative; display: flex; flex-direction: column; gap: var(--space-sm); padding: var(--space-lg); }
.panels h3 { max-width: 32ch; font-size: var(--text-xl); }
.panels p { max-width: 46ch; color: var(--color-muted); font-size: var(--text-md); line-height: 1.5; }
.seam { position: absolute; background: var(--color-rule); }
.seam-h { left: 0; right: 0; top: 0; height: 1px; transform-origin: 0 50%; }
.seam-v { display: none; top: 0; bottom: 0; left: 0; width: 1px; transform-origin: 50% 0; }

/* close: a band, a Split. The big head is wiped in by the scroll on 40rem and up (js/site.js) */
.cta { background: var(--color-paper-2); border-top: var(--rule-hair) solid var(--color-rule); color: var(--color-ink); }
.close-h { max-width: 16ch; font-size: var(--text-display-s); line-height: 1.04; }
.close-act { display: grid; gap: var(--space-md); justify-items: start; }
/* who answers: a plain, confident statement, a step stronger than the line under it */
.close-who { max-width: 30ch; color: var(--color-ink); font-size: var(--text-lg); font-weight: 500; line-height: 1.35; }
.cta .email { font-size: var(--text-md); color: var(--color-muted); }
.cta .email a { display: inline-block; padding: var(--space-sm) 0; color: var(--color-ink); text-decoration-color: var(--color-rule-2); text-underline-offset: 0.3em; overflow-wrap: anywhere; }
.cta .email a:hover { color: var(--color-accent); text-decoration-color: currentColor; }

/* ---- footer: a mast, the wordmark large over one row ---- */
.site-footer { padding-block: var(--space-xl) calc(var(--space-lg) + env(safe-area-inset-bottom)); /* the phone bar steps aside while the footer shows (js/site.js), so it needs no room at the end */ border-top: var(--rule-hair) solid var(--color-rule); background: var(--color-paper-3); color: var(--color-ink); }
.foot { display: grid; gap: var(--space-lg); }
.foot-brand { display: flex; align-items: center; gap: 0.18em; color: var(--color-ink); font-size: clamp(1rem, 11vw, 7.5rem); line-height: 1; }
.foot-brand svg { width: 1em; height: 1em; flex: none; }
.foot-brand .wordmark { font-size: 1em; }
.foot-row { display: grid; gap: var(--space-sm); padding-top: var(--space-md); border-top: var(--rule-hair) solid var(--color-rule); }
.foot-links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2xs) var(--space-lg); }
.foot-links .nav-link { padding-inline: 0; overflow-wrap: anywhere; } /* the address breaks only when a very narrow screen leaves it no other way */
.privacy { display: grid; gap: var(--space-2xs); color: var(--color-muted); font-size: var(--text-sm); }
.privacy p { text-wrap: balance; } /* two even lines on phones, never "of visits." alone */

/* ---- sticky bar for phones: the WhatsApp button, once the hero's button has gone. An enhancement: js/site.js sets html[data-js]; without it the bar is not there ---- */
.sticky-bar { display: none; }
[data-js] .sticky-bar { display: block; position: fixed; inset: auto 0 0 0; z-index: var(--z-sticky); padding: var(--space-sm) var(--gutter) calc(var(--space-sm) + env(safe-area-inset-bottom)); border-top: var(--rule-hair) solid var(--color-rule); background: var(--color-paper-2); transform: translateY(100%); visibility: hidden; transition: transform var(--dur-short) var(--ease-out), visibility 0s linear var(--dur-short); }
[data-js] .sticky-bar.is-on { transform: none; visibility: visible; transition-delay: 0s; }
.sticky-bar .btn { display: flex; width: 100%; }

/* the narrowest phones: the pill keeps its logo and Sign in on one line */
@media (max-width: 22.5rem) {
  .pill { column-gap: var(--space-xs); }
  :root { --bg: 8; }
}
/* 200% zoom and more (a 240px screen or less): the brand is a little smaller and Sign in steps down to a second row of the pill rather than vanishing */
@media (max-width: 15rem) {
  :root { --bm: 24; --bg: 6; --bw: 16; }
  .pill { padding-inline: var(--space-xs); }
}

/* a phone held sideways (a short, wide screen): the nav pill and the WhatsApp bar are slimmer, so the tour's phone has room beside its steps (css/tour.css) */
@media (max-width: 63.99rem) and (max-height: 32.5rem) and (orientation: landscape) {
  :root { --bar-h: 62px; }
  .site-header > .container { padding-top: var(--space-xs); }
  .pill { min-height: 56px; padding-block: var(--space-3xs); }
  [data-js] .sticky-bar { padding-block: var(--space-xs) calc(var(--space-xs) + env(safe-area-inset-bottom)); }
  .sticky-bar .btn { min-height: 44px; }
}

/* ---- tablet and up ---- */
@media (min-width: 48rem) {
  :root { --bw: 22; }
  .section { padding-block: var(--space-3xl); }
  .problem { padding-block: var(--space-3xl); }
  .problem .split { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); grid-template-rows: auto 1fr; align-items: start; }
  .problem h2 { grid-column: 1; grid-row: 1; }
  .problem-line { grid-column: 1; grid-row: 2; align-self: end; margin-top: 0; }
  .thread { grid-column: 2; grid-row: 1 / span 2; }
  .panels { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .panels li { padding: var(--space-xl); }
  .panels li:nth-child(2) .seam-h { display: none; }
  .seam-v { display: block; }
  .cta .split { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .site-footer { padding-top: var(--space-2xl); }
  .foot { gap: var(--space-xl); }
  .foot-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; padding-top: var(--space-lg); }
  .privacy { justify-self: end; text-align: right; }
}

/* the primary action joins the pill; the phone bar goes */
@media (min-width: 60rem) {
  .pill-end .btn { display: inline-flex; }
  [data-js] .sticky-bar { display: none; }
  .site-footer { padding-bottom: var(--space-2xl); }
}

/* laptops: the owner's screen leads, under a head set in two parts. The hero is one screen: the screen sits in a window that fills what the head leaves,
   sized by js/overview.js so its lower edge falls between two blocks of the app. Its lower part is reached by scrolling the window, or by the pinned runway. */
@media (min-width: 64rem) {
  .hero { box-sizing: border-box; display: flex; min-height: calc(100svh - var(--chrome-h)); padding-block: var(--space-sm) var(--space-xs); }
  .hero > .container { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
  .opener { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); column-gap: var(--gap-columns); margin-bottom: var(--space-lg); }
  /* the picture needs 26rem, but on a short screen only what keeps the hero above the fold: the head (about 260px with the notice and the pill) stays, and the picture starts a little way down instead */
  .hero-visual { display: flex; flex-direction: column; flex: 1 1 0; min-height: max(14rem, min(26rem, calc(100svh - 280px))); }
  /* a wide screen: the picture is as wide as its column allows and its window ends before the screen does, so the hero ends with the window (js/overview.js sets .is-hug) */
  .hero.is-hug { min-height: 0; }
  .hero.is-hug .hero-visual { flex: none; }
  .hero.is-hug .ovb { flex: none; height: var(--ovb-wh); }
  .tour-phone.hero-phone { display: none; }
  .ovb { display: block; flex: 1 1 0; min-height: 0; }
  .js .spine { display: block; position: fixed; inset-block: 0; left: max(var(--space-md), 2vw); z-index: var(--z-raised); width: 2px; background: var(--color-rule); pointer-events: none; }
  .problem { display: flex; align-items: center; min-height: 100svh; padding-block: var(--space-3xl) var(--space-2xl); }
  .problem-pin { flex: 1 1 auto; }
  .thread-msgs li { font-size: var(--text-2xl); }
  .problem-line { font-size: var(--text-3xl); }
}
@media (min-width: 64rem) and (max-height: 52rem) { /* a short laptop screen (832px or less): the pinned chapter still fits in one screen, and the head gives the owner's screen back some room so its top edge stays between two blocks */
  .thread-msgs li { font-size: var(--text-xl); }
  .opener { margin-bottom: var(--space-md); }
  .opener-act { gap: var(--space-sm); }
}

/* ---- load intro: a full-screen cover on the paper. The V's right arm starts at the far end of where the name will be and sweeps back across it while the left arm returns; they lock into the V, the frame closes around them,
   the two gold bars light up in a soft glow, the name wipes out from the mark; then the whole logo floats to the header's brand, the cover fades out beneath it, and the header's own brand takes over (js/site.js, GSAP). It exists only under html.js, which the head script adds only when "reduce motion" is off;
   without script, or if the script never runs, it is not there or it fades out of its own accord at 2.4 s, so it can never stay up. The start states are here so the finished logo never flashes before the timeline starts.
   The lockup is laid out like the header's brand (the same --bm, --bg and --bw numbers, which change with the width), all multiplied by --lu, so the flight is one uniform scale of 1/--lu and the glyphs line up. ---- */
.intro { display: none; }
.js .intro { display: grid; place-items: center; position: fixed; inset: 0; z-index: var(--z-modal); color: var(--color-ink); animation: intro-away 200ms linear 2400ms both; }
@keyframes intro-away { from { opacity: 1; visibility: visible; } to { opacity: 0; visibility: hidden; } }
.intro-bg { position: absolute; inset: 0; background: var(--color-paper); }
.intro-logo { --lu: clamp(1.2px, 0.5vw, 4.6px); position: relative; display: flex; align-items: center; gap: calc(var(--bg) * var(--lu)); line-height: 1; }
.intro-logo svg { position: relative; width: calc(var(--bm) * var(--lu)); height: calc(var(--bm) * var(--lu)); flex: none; overflow: visible; }
.intro-logo .wordmark { font-size: calc(var(--bw) * var(--lu)); }
.intro-glow { position: absolute; left: calc(14 * var(--lu)); top: calc(14 * var(--lu)); width: calc(64 * var(--lu)); height: calc(64 * var(--lu)); margin: calc(-32 * var(--lu)) 0 0 calc(-32 * var(--lu)); border-radius: 50%; background: radial-gradient(closest-side, color-mix(in oklab, var(--color-accent) 35%, transparent), transparent); pointer-events: none; } /* behind the mark, on the gold bars; opacity and scale only */
.js .in-frame, .js .in-arm, .js .in-bar, .js .intro-glow { opacity: 0; }
.js .in-word { clip-path: inset(-5% 100% -5% -2%); }
/* the header's brand waits, laid out and invisible, under the cover until the logo lands on it (js/site.js sets .intro-on and always removes it) */
.js.intro-on .site-header .brand { opacity: 0; }
/* a slow start (the styles arrived after 0.9 s: the inline script right after the cover) skips the intro and its blank cover altogether, so the page shows as soon as it can */
.no-intro .intro { display: none; }

@media (prefers-reduced-motion: reduce) {
  [data-js] .sticky-bar { transition: none; }
}
