/* ============================================================================================
   The landing page: Components/Landing/LandingPage.razor, which is the whole of "/" and the only
   page this sheet serves. Four other media variants were built and reviewed against it ("/alt",
   "/v3", "/v4", "/v5" — screenshots, drawn panels, drawn and framed, baked to files) and this is
   the one that won: baked WebP renders of Mock.razor, framed in a browser bar, on white.

   This sheet does NOT reuse map.css's tokens, and that is deliberate — twice over.

   First, the app's palette follows a per-visitor Light/Dark setting resolved by map.js, and a landing
   page that changed colour scheme under a stranger is a landing page whose composition cannot be
   designed. So it declares its own, one fixed scheme.

   Second, the page's ground has to be clearly separable from the product's, and three attempts failed
   before this one. All three failures were the same failure: a page at #faf6f0 holding panels at
   #faf7f2 is one colour, and so is a near-white page at #fdfbf7 — two points of lightness apart. A
   cool grey page did separate them, and read as a different brand. Clay separated them too, but with
   the product's screens as the brightest thing in the frame.

   What works is the relationship TURNED AROUND: the page is white and near-black, the screens are
   dimmed a few points on the way in, and a screenshot becomes a DARKER object resting on a bright
   page — which is how a printed plate sits on a page, and how software is photographed. Every warm
   thing on the page now belongs to the product: the screens, the terracotta, the jade pins. The page
   around them carries none, and that is what keeps the two apart.

   Three ideas carry the whole design:
     - ONE type ramp. Display down to caption in six steps with real distance between them, so a
       reader who only sees headings still gets the argument.
     - ALTERNATING GROUND. Ink, paper, ink. A page on one surface reads as one undifferentiated
       scroll no matter what is written on it.
     - A SINGLE MEDIA FRAME. Every picture of the product sits in the same plate, under the same
       browser bar, dimmed by the same amount.
   ============================================================================================ */

.ln {
  /* --- ground. White and near-black, carrying no warmth at all: see the note above. The screens
     are the only warm thing in the frame, which is what tells a reader where the page stops. --- */
  --paper: #ffffff;         /* the page */
  --paper-2: #f6f6f7;       /* raised band, for the process and the numbers */
  --card: #ffffff;          /* a surface on top of paper */
  --line: #e4e4e7;
  --line-2: #cfcfd4;
  --ink: #0e0e11;           /* the dark bands */
  --ink-rgb: 14, 14, 17;    /* the same, as channels, for the hero's veil */
  --ink-2: #17171b;         /* a surface on top of ink */
  --ink-line: rgba(255, 255, 255, .13);

  /* --- text --- */
  --tx: #0d0d10;
  --tx-2: #4b4b52;
  --tx-3: #86868d;
  --on-ink: #f4f4f6;
  --on-ink-2: #b4b4bc;
  --on-ink-3: #85858e;

  /* --- accent. The product's terracotta, in two values: the bright one carries buttons and
     anything sitting on ink, the deep one is the AA-safe version for accent TEXT on paper. --- */
  --br: #cf7143;
  --br-deep: #a04a14;       /* AA on white */
  --br-wash: #fbdcc0;       /* the highlighter, under a lead phrase and in one heading */

  /* The hero's 13k dots, read from here by js/landing.js. The product's own available-pin jade
     (PIN_COLORS in js/map/constants.js) at a higher lightness, because here it sits on a dimmed
     basemap instead of a bright one — the hue is what a returning visitor recognises. */
  --ln-pin: hsl(166, 70%, 46%);

  /* --- type ramp.
     Two faces, and the split is the same idea as the palette: the TITLES are set in a serif, which no
     interface on earth uses for a control, so the page's own voice can never be mistaken for the
     product's. Everything a reader actually reads at length — body, lists, captions, questions — stays
     in the grotesk, where it is easiest. --- */
  --f: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --f-display: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
  --fs-display: clamp(2.6rem, 1.3rem + 5.2vw, 5rem);
  --fs-h2: clamp(1.9rem, 1.25rem + 2.6vw, 3.1rem);
  --fs-h3: clamp(1.3rem, 1.15rem + .6vw, 1.6rem);
  --fs-lede: clamp(1.125rem, 1rem + .75vw, 1.5rem);
  --fs-body: 1.0625rem;
  --fs-sm: .9375rem;
  --fs-xs: .8125rem;

  /* --- rhythm --- */
  --gut: clamp(20px, 5vw, 40px);
  --sec: clamp(76px, 9vw, 148px);
  --r: 16px;                 /* the one corner radius, on plates and cards */
  --shadow: 0 1px 2px rgba(10, 10, 14, .07), 0 16px 34px -12px rgba(10, 10, 14, .22);
  --shadow-lg: 0 2px 6px rgba(10, 10, 14, .09), 0 40px 76px -24px rgba(10, 10, 14, .3);

  background: var(--paper);
  color: var(--tx);
  font-family: var(--f);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* The document behind the page. The footer is ink, so an overscroll past the bottom should be ink
   too rather than flashing the app's own background through. */
body:has(.ln) { background: #0e0e11; }

/* Bootstrap's reboot is linked ahead of this sheet and sets margins and a line-height chosen for a
   form layout; everything below states its own. */
/* :where() so the reset carries NO specificity of its own: every margin a class below sets would
   otherwise lose to `.ln p`, silently, and the page would collapse its own vertical rhythm. */
.ln :where(h1, h2, h3, h4, p, ul, ol, figure) { margin: 0; padding: 0; }
.ln ul, .ln ol { list-style: none; }
.ln a { color: inherit; text-decoration: none; }
.ln img { display: block; max-width: none; }
.ln ::selection { background: var(--br); color: #fff; }

/* ---------------------------------------------------------------------------- type -------- */

/* The serif runs at a lighter weight and far less negative tracking than the grotesk would: its
   strokes already carry the contrast that Inter needs weight for, and tightening it closes the
   counters. */
.ln-display, .ln-h2, .ln-feature-h, .ln-closing, .ln-prose .ln-spine {
  font-family: var(--f-display); font-optical-sizing: auto;
}
.ln-display {
  font-size: var(--fs-display); font-weight: 500; line-height: 1.04;
  letter-spacing: -0.02em; text-wrap: balance;
}
.ln-h2 {
  font-size: var(--fs-h2); font-weight: 500; line-height: 1.1;
  letter-spacing: -0.018em; text-wrap: balance;
}
.ln-h3 { font-size: var(--fs-h3); font-weight: 600; line-height: 1.25; letter-spacing: -0.02em; }
.ln-lede { font-size: var(--fs-lede); line-height: 1.42; letter-spacing: -0.015em; color: var(--tx-2); text-wrap: pretty; }
.ln-p { color: var(--tx-2); max-width: 62ch; text-wrap: pretty; }
.ln-p + .ln-p { margin-top: 1em; }

/* A section's opening: eyebrow, heading, optional lede, always in that order with the same gaps,
   so every section down the page starts the same way. */
.ln-head { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.ln-head .ln-lede { max-width: 36ch; }
/* Measured in the HEADING's own ch, not the body's. The head used to cap itself at 42 body characters,
   which is about half of what a 3rem serif line needs — so every title on the page broke in the middle
   of a clause ("How RentMapped / works") with the column beside it standing empty. */
.ln-head .ln-h2 { max-width: 20ch; }
.ln-head-center { align-items: center; text-align: center; margin-inline: auto; }
.ln-head-center .ln-h2 { max-width: 22ch; }

/* ------------------------------------------------------------------------ structure -------- */

.ln-wrap { width: 100%; max-width: calc(1200px + var(--gut) * 2); margin-inline: auto; padding-inline: var(--gut); }
.ln-wrap-narrow { max-width: calc(780px + var(--gut) * 2); }

.ln-sec { padding-block: var(--sec); }

/* One step up from paper, for the bands that hold the process and the numbers. */
.ln-raise { background: var(--paper-2); border-block: 1px solid var(--line); }

/* Ink. Everything inside flips to the on-ink tokens in one place, so a section can move between
   grounds without rewriting its contents. */
.ln-dark {
  background: var(--ink); color: var(--on-ink);
  --tx: var(--on-ink); --tx-2: var(--on-ink-2); --tx-3: var(--on-ink-3);
  --line: var(--ink-line); --line-2: rgba(255,255,255,.18);
  --card: var(--ink-2); --br-deep: #e8a075; --br-wash: rgba(207,113,67,.34);
}

/* ------------------------------------------------------------------------- controls -------- */

.ln-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 26px; border-radius: 999px; border: 1px solid transparent;
  background: var(--br); color: #fff;
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600; letter-spacing: -.01em;
  white-space: nowrap; cursor: pointer;
  box-shadow: 0 1px 2px rgba(97, 45, 13, .2), 0 10px 22px -10px rgba(97, 45, 13, .55);
  transition: transform .15s cubic-bezier(.2,.8,.3,1), box-shadow .15s ease, background-color .15s ease;
}
.ln-btn:hover { background: #d97e51; color: #fff; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(97,45,13,.22), 0 16px 30px -12px rgba(97,45,13,.6); }
.ln-btn:active { transform: translateY(0); }
.ln-btn-sm { padding: 10px 18px; font-size: var(--fs-xs); }
.ln-btn-lg { padding: 18px 34px; font-size: 1.0625rem; }
.ln-btn .ln-arrow { transition: transform .15s ease; }
.ln-btn:hover .ln-arrow { transform: translateX(3px); }

/* The quiet second action. Never a competing colour: an outline that reads as "or keep reading". */
.ln-btn-ghost { background: transparent; color: var(--tx); border-color: var(--line-2); box-shadow: none; }
.ln-btn-ghost:hover { background: transparent; color: var(--tx); border-color: var(--tx-3); transform: translateY(-1px); box-shadow: none; }

.ln-actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }

/* ---------------------------------------------------------------------- 0 — top bar -------- */

/* Two items, and never more: the mark, and the one destination every link on this page shares.
   (docs/landing-copy-v7.md section 0 — that IS the nav, in full.)

   Not there at all until the hero's own row has scrolled past, then it slides in carrying the same
   pair. Two states of one bar rather than two bars on one screen, which is what buys the first screen
   enough room to show the map instead of talking over it. js/landing.js adds .on. */
.ln-top {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  background: color-mix(in srgb, var(--ink) 80%, transparent);
  backdrop-filter: saturate(160%) blur(14px); -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid var(--ink-line);
  transform: translateY(-100%); opacity: 0; pointer-events: none;
  transition: transform .26s cubic-bezier(.2,.8,.3,1), opacity .2s ease;
}
.ln-top.on { transform: none; opacity: 1; pointer-events: auto; }
.ln-top-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; height: 60px; }
/* The wordmark carries the map sidebar's chrome — a top border, and the padding that separates it
   from the filter groups. Neither belongs here. */
.ln .brandmark { border-top: none; padding: 0; align-items: flex-start; gap: 2px; font-family: "Nunito", var(--f); }
.ln-top .brandmark, .ln-foot .brandmark { color: var(--on-ink); }
.ln-top .brandmark-tagline, .ln-foot .brandmark-tagline { color: var(--on-ink-3); }

/* ------------------------------------------------------------------------- 1 — hero -------- */

.ln-hero {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: min(860px, 100svh);
  display: flex; flex-direction: column;
}
/* The same pair as the bar that replaces it on scroll: the mark, and the map. The big button is NOT
   here — it belongs under the argument it answers (see .ln-case), and the reader who wants the map
   before reading any of it has this one. */
.ln-hero-top {
  position: relative; z-index: 2; padding-top: 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}

/* Every rental in the region, one dot each, drawn once onto a canvas by js/landing.js from a baked
   snapshot. The density IS the claim, which is why it is drawn rather than screenshotted: it stays
   crisp at any pixel ratio, and it costs no query. */
.ln-hero-map { position: absolute; inset: 0; z-index: 0; }
/* Dimmed, but nowhere near as far as it was: this is the one picture on the page that IS the
   argument, and under the old veil the pins could not be made out at all. Greyscale stays, so the
   pins' jade is the only colour in the frame. */
.ln-hero-map .leaflet-tile-pane { filter: grayscale(1) brightness(.62) contrast(1.02); }
.ln-hero-map .leaflet-container { background: var(--ink); }
.ln-hero-map .leaflet-control-attribution {
  background: rgba(0,0,0,.4); color: #9c9086; font-size: 10px; border-radius: 6px 0 0 0;
}
.ln-hero-map .leaflet-control-attribution a { color: #bfae9e; }
/* Just enough to hold the type legible and to land the band on the section below without a seam —
   the middle of the frame is left almost clear, because that is where the pins are. */
.ln-hero-veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(104% 68% at 50% 44%, rgba(var(--ink-rgb),.06) 0%, rgba(var(--ink-rgb),.40) 62%, rgba(var(--ink-rgb),.74) 100%),
    linear-gradient(to bottom, rgba(var(--ink-rgb),.72) 0%, rgba(var(--ink-rgb),0) 18%, rgba(var(--ink-rgb),0) 62%, rgba(var(--ink-rgb),.86) 90%, var(--ink) 100%);
}
/* Title at the TOP, the line at the BOTTOM, and the middle left empty on purpose: that gap is where
   the centre of Cebu sits, and the one thing this screen has to do is let a stranger see the mass of
   pins before reading a word about it. Nothing may be added between the two — the previous version
   centred both and put a button between them, and the city was behind the type. */
.ln-hero-body {
  position: relative; z-index: 2; flex: 1;
  display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center;
  gap: clamp(40px, 14vh, 150px);
  padding-top: clamp(28px, 6vh, 64px); padding-bottom: clamp(40px, 8vh, 96px);
}

.ln-hero-title { display: flex; flex-direction: column; align-items: center; gap: clamp(14px, 2vh, 22px); }
.ln-hero h1 { max-width: 15ch; text-shadow: 0 2px 30px rgba(0,0,0,.6), 0 1px 3px rgba(0,0,0,.35); }
/* Deliberately almost invisible: it is there for the reader who stops to ask what "every rental" covers,
   and for nobody else. Tracked out and set small so it reads as a label on the title rather than as a
   second line of copy competing with it. */
.ln-kinds {
  font-size: var(--fs-xs); letter-spacing: .18em; font-weight: 500;
  color: rgba(255,255,255,.58); text-shadow: 0 1px 3px rgba(0,0,0,.9), 0 1px 16px rgba(0,0,0,.9);
}
@media (max-width: 420px) { .ln-kinds { letter-spacing: .1em; } }
.ln-hero .ln-quote { text-shadow: 0 1px 20px rgba(0,0,0,.65); }

/* The italic line under the H1, which docs/landing-copy-v7.md sets as the hero's second of four
   levels. Set as a quotation rather than as a lede: it is the only sentence on the page written from
   the reader's side rather than ours, and italic serif is what says so.
   Its two sentences are two LINES, because the second is the turn — the whole line exists to land
   "It was", in the past, on a reader who is about to be shown the thing that ended it. */
.ln-quote {
  display: flex; flex-direction: column; gap: .18em;
  font-family: var(--f-display); font-style: italic; font-weight: 400;
  font-size: clamp(1.2rem, 1rem + 1.1vw, 1.75rem); line-height: 1.34; letter-spacing: -.005em;
  color: var(--on-ink); max-width: 48ch;
}
/* Balanced per SENTENCE, not across the pair: left to itself the first one broke after "nothing" and
   dropped "to rent." onto a line of its own. */
.ln-quote span { text-wrap: balance; }

/* --------------------------------------------------------------------- 2 — the case -------- */

/* The opening argument, on ink so it reads as the back half of the hero rather than the start of
   the product tour. The complaint, then the two claims that answer it, then the button.

   Nothing comes between the hero's line and these four sentences: the line says "a lottery" and these
   four are what makes it one. An earlier version had the big button sitting in that gap and the
   explanation arrived detached from the thing it explains. */
.ln-case { padding-bottom: var(--sec); }
.ln-case .ln-lede { max-width: 38ch; color: var(--on-ink); font-weight: 500; }
/* Four sentences, four lines, no markers: it is a list and should look like one, but a bulleted list
   would turn the page's opening argument into a spec sheet. */
.ln-lines { display: flex; flex-direction: column; gap: .42em; }

/* A new block, and it has to arrive as one. A rule across the full measure and a lot of air above it:
   the per-claim hairlines that used to do this read as two column headings of the SAME block, so the
   first claim looked like the fifth complaint. */
.ln-claims {
  display: grid; gap: clamp(34px, 4vw, 56px);
  margin-top: clamp(66px, 9vw, 116px); padding-top: clamp(38px, 4.5vw, 60px);
  border-top: 1px solid var(--ink-line);
  grid-template-columns: 1fr;
}
@media (min-width: 860px) { .ln-claims { grid-template-columns: 1fr 1fr; gap: clamp(40px, 5vw, 76px); } }
/* Stacked, the second claim needs a line of its own back; side by side the column gap does it. */
@media (max-width: 859px) { .ln-claim + .ln-claim { border-top: 1px solid var(--ink-line); padding-top: 30px; } }
.ln-claim h2 { font-size: clamp(1.4rem, 1.15rem + 1vw, 1.9rem); font-weight: 600; line-height: 1.18; letter-spacing: -.025em; }
.ln-claim p { margin-top: 14px; color: var(--on-ink-2); font-size: var(--fs-sm); max-width: 46ch; }
.ln-claim b { color: var(--on-ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* "Take control." on a line of its own, in the accent, and in the page's own serif — the face the H1
   is set in and the one no interface uses for a control. It is the only imperative in the whole copy and
   a colon buried it: the eye ran straight through into the sentence it introduces and the call was gone.
   Set a size up, because a serif at the grotesk's size reads smaller than it is. */
.ln-claim-call {
  display: block; margin-bottom: .22em;
  font-family: var(--f-display); font-optical-sizing: auto;
  font-size: 1.22em; font-weight: 500; line-height: 1.1; letter-spacing: -.015em;
  color: var(--br);
}

/* The one button on this screen, under the argument it answers rather than above it. The nav's own
   button (see .ln-hero-top) is what serves a reader who wants the map before reading any of this. */
.ln-case .ln-actions { margin-top: clamp(42px, 5.5vw, 70px); }

/* The highlighter, the same one the capability lines wear under their lead phrase (.ln-list b), on
   ONE phrase in ONE heading. These two claims are the most important sentences on the page and they
   were arriving as an even grey wall; a reader scanning headings now has somewhere to land. */
.ln-mark {
  background-image: linear-gradient(to bottom, transparent 0 20%, var(--br-wash) 20% 97%, transparent 97%);
  padding-inline: 5px; margin-inline: -3px;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}

/* ------------------------------------------------------------------ 3 — how it works ------- */

/* The steps and the panel they produce, side by side on a wide screen, and the section's own title
   standing still beside both — the same mechanic section 5 uses, and for the same reason: a reader deep
   in a long section should never have to scroll back to find out what it is about.

   The title column is the LAST thing to appear, not the first: three columns need the room for it, and
   below that width the steps matter more than the pinning does.

   The picture's track is a fixed width and never "auto". With auto it took the max-content of what is
   in it — a caption, one long line — and the steps collapsed to a third of their width with the heading
   running out across the picture. A track that cannot be stretched by its contents is the fix, not a cap
   on the contents, because the next long caption would do it again. */
.ln-how { display: grid; gap: clamp(40px, 4.5vw, 64px); }
@media (min-width: 1040px) {
  .ln-how { grid-template-columns: minmax(0, 1fr) minmax(0, 420px); align-items: start; }
  .ln-how > .ln-head { grid-column: 1 / -1; }
}
@media (min-width: 1240px) {
  .ln-how { grid-template-columns: minmax(0, 280px) minmax(0, 1fr) minmax(0, 420px); }
  .ln-how > .ln-head { grid-column: auto; position: sticky; top: 118px; }
}

/* Always a vertical stack now, at every width. Six across the page was a handsome rail and a bad read:
   the eye had to travel the whole width for each step, and the steps are a sequence. */
.ln-steps { display: grid; gap: 0; grid-template-columns: 1fr; }

.ln-step { position: relative; display: grid; grid-template-columns: 46px 1fr; gap: 18px; padding-bottom: 30px; }
.ln-step-top { position: relative; display: flex; align-items: center; height: 46px; }
/* The run between one station and the next, drawn off the STEP and not off the icon's own 46px box:
   the row is as tall as the text beside it, and a line measured from the icon stopped a third of the way
   down and ended in mid-air. */
.ln-step::after {
  content: ""; position: absolute; left: 23px; top: 46px; bottom: 0; width: 1px;
  background: var(--line-2); opacity: .8; transform: translateX(-.5px);
}
.ln-step:last-child::after { display: none; }
.ln-step-dot {
  position: relative; z-index: 1; flex: 0 0 auto;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--card); border: 1px solid var(--line-2); color: var(--br-deep);
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 14px -8px rgba(10,10,14,.35);
}
.ln-step-dot svg { width: 21px; height: 21px; }
.ln-step-n {
  position: absolute; z-index: 2; top: -3px; left: 34px;
  min-width: 19px; height: 19px; padding: 0 5px; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--br); color: #fff; font-size: 11px; font-weight: 700; line-height: 1;
}
.ln-step-body { padding-top: 9px; }
.ln-step-body h3 { font-size: 1.0625rem; font-weight: 600; letter-spacing: -.015em; }
.ln-step-body p { margin-top: 8px; font-size: var(--fs-sm); line-height: 1.5; color: var(--tx-2); max-width: 64ch; }
.ln-step-body i { font-style: italic; color: var(--tx); }
.ln-step-body b { font-weight: 600; color: var(--tx); font-variant-numeric: tabular-nums; }

/* What the six steps produce. Centred below them on a narrow screen, beside them on a wide one. */
.ln-how-proof { display: flex; justify-content: center; }
.ln-how-proof .ln-shot { max-width: 420px; }

/* The panel does not end, it is cut off: the ad list goes on. The teeth are cut out of the PLATE and
   not baked into the picture, and that is the whole trick — a tooth baked into a file has to be painted
   some colour, and the only right colour is the mount behind it, which is the one thing a file cannot
   know. Baked, it came out as a zigzag with a flat strip of panel under it and then a straight edge:
   two cuts where there should be one. Masked, the page really does show through.
   The teeth match the baked cut across the middle, so both read as the same saw. */
.ln-how-proof .ln-plate {
  border-bottom: 0;
  border-end-start-radius: 0;
  border-end-end-radius: 0;
  /* Two layers: the plate itself, nine pixels short, and a strip of teeth along the bottom. Longhands
     and not the `mask` shorthand — a shorthand built out of var() and a calc() size was dropped whole by
     the parser and the panel simply came out cut off flat. The tooth is an SVG path rather than the
     conic-gradient recipe for the same reason: the recipe is easy to get backwards (the first attempt
     put the wedge outside the tile), and a path says what it means. */
  -webkit-mask-image: linear-gradient(#000, #000), url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='16'%20height='9'%3E%3Cpath%20d='M0,0%20L8,9%20L16,0%20Z'/%3E%3C/svg%3E");
  mask-image: linear-gradient(#000, #000), url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='16'%20height='9'%3E%3Cpath%20d='M0,0%20L8,9%20L16,0%20Z'/%3E%3C/svg%3E");
  -webkit-mask-size: 100% calc(100% - 9px), 16px 9px;
  mask-size: 100% calc(100% - 9px), 16px 9px;
  -webkit-mask-repeat: no-repeat, repeat-x;
  mask-repeat: no-repeat, repeat-x;
  -webkit-mask-position: top, bottom;
  mask-position: top, bottom;
}

/* --------------------------------------------------------- 4 — what you can do with it ----- */

/* Three features, each a run of pairs. Pictures and lines swap sides from one feature to the next —
   the cheapest way to stop a desktop page reading as one column of stacked blocks. */
/* The section's title sits beside its features but does not stick; the lines of each pair do instead.
   Narrower than section 3's column because the words are shorter, and because every pixel it does not
   take is a pixel the panels keep. */
.ln-find { display: grid; gap: clamp(44px, 5vw, 76px); }
@media (min-width: 1240px) {
  .ln-find { grid-template-columns: minmax(0, 210px) minmax(0, 1fr); column-gap: 56px; align-items: start; }
}
.ln-features { min-width: 0; }
.ln-feature + .ln-feature { margin-top: clamp(80px, 10vw, 150px); }
.ln-feature-lede { max-width: 34ch; margin-top: 16px; }
/* One word, set large: at this size "Find" is a section title and needs nothing under it. A step down
   from the section's own heading so the two levels never read as equals. */
.ln-feature-h { font-size: clamp(1.85rem, 1.25rem + 2.1vw, 2.6rem); }
/* One picture beside the lines it answers, and that pairing is what let the captions go: a picture
   standing in a column of pictures needed a caption just to say which lines it belonged to. */
.ln-pair { display: grid; gap: clamp(26px, 4vw, 56px); align-items: center; margin-top: clamp(34px, 4.5vw, 60px); }
@media (min-width: 980px) {
  .ln-pair { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  /* Flipped, the COLUMNS flip with the order — otherwise the picture lands in the narrow one and is
     squeezed below the width it was baked at, which is the one thing these panels must not be. */
  .ln-feature-flip .ln-pair { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .ln-feature-flip .ln-pair-text { order: 2; }
  .ln-feature-flip .ln-pair-media { order: 1; }
  /* The lines stand still while the panel beside them scrolls past, and go when the pair ends. The
     section's own title does not: it scrolls away with the section's top. */
  .ln-pair-text { align-self: start; position: sticky; top: 118px; }
}
/* Once the title takes a column of its own, the lines give some of theirs back to the panels. */
@media (min-width: 1240px) {
  .ln-pair { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); }
  .ln-feature-flip .ln-pair { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); }
}
.ln-pair-media { min-width: 0; display: flex; }
.ln-feature-cta { margin-top: clamp(34px, 4.5vw, 56px); }

/* The capability lines. No bullet markers: the lead phrase is marked instead, which reads as a
   list without spending a gutter on dots, and lets the eye scan just the marks. */
.ln-list { display: flex; flex-direction: column; gap: 14px; }
.ln-list li { font-size: var(--fs-sm); line-height: 1.55; color: var(--tx-2); }
.ln-list b {
  font-weight: 600; color: var(--tx);
  background-image: linear-gradient(to bottom, transparent 0 24%, var(--br-wash) 24% 96%, transparent 96%);
  padding-inline: 3px; margin-inline: -2px;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
.ln-list i { font-style: italic; }

/* --------------------------------------------------------------------- media plates -------- */

/* Every picture on the page is framed the same way, and that sameness is what makes a run of panels
   read as one product rather than as a scrapbook. Barely off white: the plate is the mount, and the
   screen inside it is the only warm thing in the frame. */
.ln-plate {
  position: relative; width: 100%;
  border-radius: var(--r); border: 1px solid var(--line);
  background: linear-gradient(160deg, #fdfdfe 0%, #f4f4f6 100%);
  box-shadow: var(--shadow);
  overflow: hidden;
}

/* --- the four signals that say "this is a picture of the product".

   The problem they answer, which took four variants to solve: a panel drawn in markup is the same DOM,
   the same font and the same sharpness as the page around it, so nothing tells a visitor where the page
   stops and the app begins. They press a checkbox, nothing happens, and the site is broken. Every panel
   here is now a BAKED FILE (see below), which is the fourth signal and the strongest - there is nothing
   to press in the first place. The other three still earn their keep, and none of them costs
   legibility:
     1 · A BROWSER BAR. Not three macOS dots — those are a hint, and a hint is not enough. An address
         field with a domain in it is a statement: this is a window, photographed.
     2 · REDUCED SCALE. A live interface on this page would be at the page's own size. A panel visibly
         smaller than life reads as a reduced screenshot before anyone thinks about it.
     3 · INERT. Nothing inside takes a pointer event or a text selection, so no checkbox lights up under
         the cursor and no caret appears in a field. Hover highlights are what shout "I am alive".
   Deliberately NOT a link to the map: a visitor who pokes before reading would be thrown off the page
   before they finish it, and the explicit "Open the map" buttons already exist. --- */

/* Cool grey, where the screen inside it is warm: a browser's chrome is grey in life, and here that
   is also the line between the page and the product. Kept low - it is a frame, not a feature. */
.ln-chrome {
  display: flex; align-items: center; gap: 10px;
  padding: 0 11px; height: 30px;
  background: linear-gradient(to bottom, #e8e8eb, #dcdce1);
  border-bottom: 1px solid var(--line);
  font-size: 11px; color: var(--tx-3);
}
.ln-chrome-nav { display: flex; gap: 8px; flex: 0 0 auto; font-size: 12px; line-height: 1; opacity: .4; }
/* The domain, and nothing after it: a path means nothing to a stranger, and the field is here to say
   "this is a browser", not to route anyone. */
.ln-chrome-url {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 6px;
  height: 19px; padding: 0 10px; border-radius: 999px;
  background: #fafafb; border: 1px solid var(--line-2);
  color: var(--tx-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ln-chrome-url svg { width: 10px; height: 10px; flex: 0 0 auto; opacity: .5; }
.ln-chrome-name { flex: 0 0 auto; color: var(--tx-3); letter-spacing: .01em; }
@media (max-width: 560px) { .ln-chrome-name { display: none; } }

/* --- reduced, and set back in space. Only the FALLBACK path reaches the zoom rule below (a mock drawn
   live because scripts/bake_mocks.ps1 has not run yet); a baked file is already laid out small. --- */

/* zoom, not transform: it scales the layout box as well, so the plate shrinks with its contents and
   nothing has to be told the resulting height. 0.84 puts the product's 13px at about 11 — small, but
   the caption under each panel is what a reader actually has to take in. */
.ln-plate-scaled .mk { zoom: .84; }
@media (max-width: 767px) { .ln-plate-scaled .mk { zoom: .9; } }
.ln-plate-scaled .mk, .ln-plate-baked img { pointer-events: none; user-select: none; -webkit-user-select: none; }
/* A shade off full contrast, and — the one that matters — a few points DIMMER than the white page it
   sits on. That is the whole of why this variant won: the screens are cream, so dimmed they become a
   darker object resting on a bright page instead of a lit one glowing out of a muted one. Done here
   rather than in the bake because it is the one number worth being able to turn while looking at the
   page; bake it in with a tone flag once it settles. */
.ln-plate-scaled, .ln-plate-baked { filter: contrast(.98) saturate(1.01) brightness(.955); }

/* A plane at an angle is never mistaken for a live control. The angle follows the row it sits in, so
   on a desktop the two feature columns lean away from each other and it reads as composition rather
   than as a trick. Off below the two-column breakpoint, where there is no room for it to be anything
   but a nuisance. */
@media (min-width: 980px) {
  .ln-feature .ln-pair-media { --tilt: -5deg; }
  .ln-feature-flip .ln-pair-media { --tilt: 5deg; }
  .ln-plate-scaled, .ln-plate-baked {
    transform: perspective(1800px) rotateY(var(--tilt, 0deg));
    box-shadow: var(--shadow-lg);
  }
  /* The one beside the steps is read, not glanced at, and a tilt would cost that. Flat. */
  .ln-how-proof .ln-plate-scaled, .ln-how-proof .ln-plate-baked { transform: none; }
}

/* --- the panels as they actually ship: rendered once to WebP by scripts/bake_mocks.ps1 and served as
   files. A phone gets its own render, laid out at phone width rather than a desktop render squeezed
   down - that squeeze is what put a sideways scroll under the screenshots the first version used. --- */
/* Drawn at the width it was baked at, and the plate hugs it: each panel is the width it is in the
   product, so a preset menu does not stretch across a column it would never occupy. max-width keeps a
   narrow screen honest. */
.ln-plate-baked { width: fit-content; max-width: 100%; }
.ln-plate-baked img {
  display: block; width: calc(var(--ar-w) * 1px); max-width: 100%; height: auto;
  aspect-ratio: var(--ar-w) / var(--ar-h);
}
@media (max-width: 767px) {
  .ln-plate-baked img { width: calc(var(--ar-nw) * 1px); aspect-ratio: var(--ar-nw) / var(--ar-nh); }
}

.ln-dark .ln-plate { border-color: rgba(255,255,255,.14); background: linear-gradient(160deg, #1d1d22 0%, #141418 100%); }

/* The scroller inside the plate. Every panel is baked at a width that fits its column, so this should
   never engage - it is here for the fallback path, where a live-drawn mock on a narrow screen scrolls
   sideways rather than shrinking its own type out of the family. */
.ln-plate-view { overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; }
.ln-plate-view::-webkit-scrollbar { height: 6px; }
.ln-plate-view::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px; }

.ln-cap {
  display: flex; gap: 10px; align-items: baseline;
  margin-top: 14px; font-size: var(--fs-sm); line-height: 1.45; color: var(--tx-2);
}
.ln-cap::before { content: ""; flex: 0 0 auto; width: 14px; height: 1.5px; margin-top: .62em; background: var(--br); }
.ln-cap b { color: var(--tx); font-weight: 600; }
.ln-shot { min-width: 0; }

/* ------------------------------------------------------------------ 5 — why this exists ---- */

.ln-why-grid { display: grid; gap: clamp(36px, 5vw, 80px); }
@media (min-width: 900px) {
  .ln-why-grid { grid-template-columns: minmax(0, 22ch) minmax(0, 1fr); align-items: start; }
  .ln-why-grid .ln-head { position: sticky; top: 118px; }
}
.ln-prose { max-width: 60ch; font-size: clamp(1.0625rem, 1rem + .35vw, 1.1875rem); line-height: 1.68; color: var(--on-ink-2); }
.ln-prose p + p { margin-top: 1.3em; }
/* The lead of each claim, in full-strength ink: these four phrases are the section's spine, and a reader
   who takes in nothing else should still come away with the argument. */
.ln-prose b { color: var(--on-ink); font-weight: 600; }
/* The one line that says who the page is written for. Above the four and larger than them. */
.ln-why-lede {
  margin-bottom: 1.5em;
  font-size: clamp(1.3rem, 1.05rem + 1vw, 1.75rem); line-height: 1.34; letter-spacing: -.012em;
  color: var(--on-ink); max-width: 30ch;
}
/* The turn the section exists for, standing apart from the four claims with real air above it. Larger, in
   full-strength ink: anyone scrolling past at speed should still catch this one. */
.ln-prose .ln-spine {
  margin-top: 1.9em; margin-bottom: .2em;
  font-size: clamp(1.45rem, 1.1rem + 1.3vw, 2.1rem); font-weight: 500; line-height: 1.24;
  letter-spacing: -.012em; color: var(--on-ink);
}
.ln-closing {
  margin-top: clamp(80px, 11vw, 160px); padding-inline: var(--gut); text-align: center;
  font-size: clamp(2.4rem, 1.2rem + 5vw, 4.5rem); font-weight: 500; line-height: 1.06;
  letter-spacing: -.02em; color: var(--on-ink);
}

/* ------------------------------------------------------------------------ 6 — numbers ------ */

/* Three numerals and one line each. No icons, no charts, no rings: collected into one band they
   read as proof, scattered through a page they read as a report. */
.ln-stats { display: grid; gap: 0; }
@media (min-width: 820px) { .ln-stats { grid-template-columns: repeat(3, 1fr); } }
.ln-stat { padding: clamp(28px, 4vw, 44px) 0; border-top: 1px solid var(--line); }
@media (min-width: 820px) {
  .ln-stat { padding: 8px clamp(22px, 3vw, 44px); border-top: none; border-left: 1px solid var(--line); }
  .ln-stat:first-child { padding-left: 0; border-left: none; }
  .ln-stat:last-child { padding-right: 0; }
}
.ln-stat-n {
  font-size: clamp(3rem, 1.6rem + 6vw, 5rem); font-weight: 700; line-height: 1;
  letter-spacing: -.045em; font-variant-numeric: tabular-nums; color: var(--tx);
}
.ln-stat-t { margin-top: 18px; font-size: var(--fs-sm); line-height: 1.55; color: var(--tx-2); max-width: 34ch; }
.ln-stat-t b { font-weight: 600; color: var(--tx); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------- 7 — questions ------ */

.ln-qa { margin-top: clamp(36px, 5vw, 56px); border-top: 1px solid var(--line); }
.ln-q { border-bottom: 1px solid var(--line); }
.ln-q summary {
  display: flex; align-items: flex-start; gap: 16px; justify-content: space-between;
  padding: 22px 0; cursor: pointer; list-style: none;
  font-size: 1.0625rem; font-weight: 500; letter-spacing: -.015em; line-height: 1.4; color: var(--tx);
}
.ln-q summary::-webkit-details-marker { display: none; }
.ln-q summary:hover { color: var(--br-deep); }
.ln-q summary::after {
  content: ""; flex: 0 0 auto; width: 11px; height: 11px; margin-top: .42em;
  border-right: 1.75px solid var(--tx-3); border-bottom: 1.75px solid var(--tx-3);
  transform: rotate(45deg); transition: transform .18s ease;
}
.ln-q[open] summary::after { transform: rotate(-135deg); }
/* pre-line because one answer is two paragraphs: it admits a limit and then says what we do about it,
   and run together those are one wall of hedging. The break lives in the string so the same two
   paragraphs reach the FAQPage markup. */
.ln-q p { padding-bottom: 26px; max-width: 66ch; color: var(--tx-2); font-size: var(--fs-sm); line-height: 1.62; white-space: pre-line; }
/* Where an answer ends in something to do, the link is under the answer rather than inside it. */
.ln-q-link {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 28px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--br-deep);
  border-bottom: 1px solid transparent;
}
.ln-q-link:hover { border-bottom-color: currentColor; }

/* --------------------------------------------------------------------- 8 — closing CTA ----- */

/* The last screen: one line, one button, centred, with air on both sides. There is nothing to compare or
   scan here, so there is no layout — only the ask. */
.ln-end { text-align: center; }
.ln-end-line {
  margin-inline: auto; max-width: 24ch; margin-bottom: clamp(26px, 3vw, 36px);
  font-family: var(--f-display); font-size: clamp(1.4rem, 1.1rem + 1.4vw, 2.1rem);
  font-weight: 500; line-height: 1.22; letter-spacing: -.018em; color: var(--on-ink); text-wrap: balance;
}

/* -------------------------------------------------------------------------- 9 — footer ----- */

.ln-foot { background: var(--ink); color: var(--on-ink); border-top: 1px solid var(--ink-line); }
.ln-foot-row {
  display: flex; flex-wrap: wrap; gap: 24px; align-items: center; justify-content: space-between;
  padding-block: 36px;
}
.ln-foot nav { display: flex; flex-wrap: wrap; gap: 24px; font-size: var(--fs-sm); }
.ln-foot nav a { color: var(--on-ink-3); }
.ln-foot nav a:hover { color: var(--on-ink); }

@media (prefers-reduced-motion: reduce) {
  .ln *, .ln *::before, .ln *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}
