/* The site's components.

   One stylesheet for every page. Bonfire's ground, faces and marks, with the
   same token names and the same measured contrast ratios as titles.css —
   scoped to .lm so the two pages cannot fight over the cascade.

   This began as the lead magnet stylesheet and grew into the whole component
   layer: the signup form and its three screens are here, and every page on the
   site renders that same form. Both layouts load it, so nothing has to
   remember to.

   There is deliberately no per-page CSS hook. A page that needs its own
   stylesheet is not using the system. */

.lm {
  /* Every value comes from the root palette in screen.css, which is the select
     system's bright variant. Nothing is redefined here — a second copy of a
     hex is a second thing to keep in step, and that is exactly how the dark
     theme ended up with four slightly different greys. */
  --lm-ground:     var(--s-paper);
  --lm-ink:        var(--s-ink);
  --lm-muted:      var(--s-ink-muted);
  --lm-mark:       var(--s-ink);        /* the button fill: near-black on white.
                                           NOT the accent — blue is the selection
                                           mark's, and a blue button in the same
                                           view makes the mark stop meaning it. */
  --lm-on-mark:    var(--s-paper);
  --lm-rule:       var(--s-rule);
  --lm-surface:    var(--s-surface);
  --lm-surface-2:  var(--s-surface-2);
  --lm-field:      var(--s-paper);
  --lm-line:       var(--s-line);
  --lm-negative:   var(--s-negative);
  --lm-positive:   var(--s-positive);
  --lm-accent:     var(--s-accent);

  --lm-argument: var(--font-body);
  --lm-emphasis: var(--font-body);

  --fs-micro: 0.75rem;
  --fs-small: 0.875rem;
  --fs-body:  1rem;
  --fs-lead:  1.125rem;

  --lm-measure: 36rem;
  --lm-pad: clamp(1.15rem, 5vw, 3rem);
  --lm-ease: var(--ease);

  min-height: 100vh;
  background: var(--lm-ground);
  color: var(--lm-ink);
  font-family: var(--lm-argument);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.0625rem);
  line-height: 1.6;
}


.lm *, .lm *::before, .lm *::after { box-sizing: border-box; }
.lm [hidden] { display: none !important; }

.lm h1, .lm h2, .lm h3 {
  font-family: var(--lm-argument);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.12;
  margin: 0;
  text-wrap: balance;
}
/* One face, so emphasis is the face's own italic rather than a change of
   family. No size bump either: bonfire needed one because Fraunces and Lexend
   share a cap height, and there is only Figtree here. */
.lm em, .lm i { font-style: italic; font-weight: 600; }
/* The mark is defined once, in screen.css, as the select system's selection
   rectangle. Nothing scoped to override here. */
.lm a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }

.lm-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── the column ────────────────────────────────────────────────────────── */

.lm-col {
  max-width: var(--lm-measure);
  margin-inline: auto;
  padding: clamp(2.5rem, 9vw, 5.5rem) var(--lm-pad) 4rem;
}

/* ── the hero ──────────────────────────────────────────────────────────── */

/* The price, before the promise. Server-rendered, so a cost signal is never
   300ms late and never depends on JavaScript. */
.lm-eyebrow {
  margin: 0 0 1rem;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--lm-ink);
}
/* The rule under the eyebrow is the accent, and it is the one place blue
   appears that is not the selection mark — a 2px bar is a graphic, where the
   3.90:1 the accent measures on white is the right bar and not a text one. */
.lm-eyebrow::after {
  content: "";
  display: block;
  width: 2.25rem;
  height: 2px;
  margin-top: 0.55rem;
  background: var(--lm-accent);
}

.lm-headline { font-size: clamp(2rem, 1.35rem + 3.1vw, 3.1rem); font-weight: 900; }

.lm-sub {
  margin: 1rem 0 0;
  font-size: var(--fs-lead);
  color: var(--lm-muted);
  text-wrap: pretty;
}

/* ── the image ─────────────────────────────────────────────────────────── */

.lm-shot { margin: 2.25rem 0 0; }
.lm-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--lm-rule);
  border-radius: 10px;
  background: var(--lm-surface);
}
.lm-shot figcaption {
  margin-top: 0.6rem;
  font-size: var(--fs-small);
  color: var(--lm-muted);
}

/* ── the body: whatever the Ghost editor produced ──────────────────────── */

.lm-body { margin-top: 2.25rem; }
.lm-body > :first-child { margin-top: 0; }
.lm-body > :last-child { margin-bottom: 0; }
.lm-body p { margin: 0 0 1.1em; text-wrap: pretty; }
.lm-body h2 { margin: 2rem 0 0.75rem; font-size: clamp(1.25rem, 1.1rem + 0.8vw, 1.6rem); }
.lm-body h3 { margin: 1.5rem 0 0.5rem; font-size: 1.15rem; }
.lm-body img, .lm-body video, .lm-body iframe { max-width: 100%; height: auto; border-radius: 10px; }
.lm-body blockquote {
  margin: 1.5rem 0;
  padding-left: 1rem;
  border-left: 2px solid var(--lm-line);
  color: var(--lm-muted);
}

/* The points. A checked list reads as "what you get", which a bullet does not,
   and the mark is drawn rather than a glyph so it cannot land on a font that
   does not have it. */
.lm-body ul { list-style: none; margin: 1.35rem 0; padding: 0; }
.lm-body ul li {
  position: relative;
  margin: 0 0 0.85rem;
  padding-left: 1.85rem;
}
.lm-body ul li::before {
  content: "";
  position: absolute;
  left: 0.15rem; top: 0.52em;
  width: 0.62rem; height: 0.34rem;
  border-left: 2px solid var(--lm-positive);
  border-bottom: 2px solid var(--lm-positive);
  transform: rotate(-45deg);
}
.lm-body ol { margin: 1.35rem 0; padding-left: 1.4rem; }
.lm-body ol li { margin: 0 0 0.85rem; }

/* ── the form ──────────────────────────────────────────────────────────── */

.lm-cta { margin-top: 2.5rem; }
.lm-cta--foot { margin-top: 3rem; padding-top: 2.5rem; border-top: 1px solid var(--lm-rule); }

.lm-form { margin: 0; }

/* One column, always. Side by side, the field and the button fit or do not fit
   depending on how long the button's label is — measured, "Send me the
   framework" overshot a 480px row by twelve pixels and wrapped, so the layout
   silently changed shape between one magnet and the next. Stacked is the same
   shape at every width and every label length, and the tap target is the full
   column rather than whatever is left over. */
.lm-row { display: flex; flex-direction: column; gap: 0.6rem; }
.lm-row input[type="email"] {
  width: 100%;
  min-width: 0;
  padding: 0.85rem 1rem;
  background: var(--lm-field);
  color: var(--lm-ink);
  border: 1px solid var(--lm-line);
  border-radius: 8px;
  font: inherit;
}
.lm-row input[type="email"]::placeholder { color: var(--lm-muted); }
.lm-row input[type="email"]:focus-visible {
  outline: 2px solid var(--lm-mark);
  outline-offset: 2px;
  border-color: transparent;
}

.lm-row .lm-btn { width: 100%; }

/* Two selectors, not one, and not `.lm .lm-btn`.

   A bare `.lm-btn` is (0,1,0) and loses to `.lm a` at (0,1,1), which painted
   every link-button's label in ink on ink. Scoping it to `.lm` fixed that and
   broke something else: a post is rendered by the `default` layout, which has
   no `.lm` wrapper, so its signup button fell back to the browser's grey.

   So: the plain class for a button anywhere, plus `.lm a.lm-btn` at (0,2,1)
   purely to outrank `.lm a` where a button happens to be a link. */
.lm-btn,
.lm a.lm-btn {
  padding: 0.85rem 1.5rem;
  background: var(--lm-mark);
  color: var(--lm-on-mark);
  border: 0;
  border-radius: 8px;
  font: inherit;
  font-weight: 700;
  letter-spacing: -0.01em;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}
.lm-btn[disabled] { opacity: 0.5; cursor: default; }
@media (prefers-reduced-motion: no-preference) {
  .lm-btn { transition: transform 120ms var(--lm-ease), opacity 120ms ease; }
  .lm-btn:not([disabled]):hover { transform: translateY(-1px); }
}

.lm-fine {
  margin: 0.85rem 0 0;
  min-height: 1.4em;
  font-size: var(--fs-small);
  color: var(--lm-muted);
}
.lm-fine.is-error { color: var(--lm-negative); }

/* The honeypot. Off screen rather than display:none, which some bots skip. */
.lm-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.lm-colophon {
  display: block;
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--lm-rule);
  font-size: var(--fs-small);
  color: var(--lm-muted);
}

/* ── the thank you ─────────────────────────────────────────────────────── */

/* It replaces the page rather than appearing under it. Someone who has just
   given an email has one question — where is the thing — and a screen that
   still shows the pitch answers a question nobody is asking. */
.lm-thanks { padding: clamp(3rem, 12vw, 7rem) var(--lm-pad) 4rem; }
.lm-thanks-in { max-width: var(--lm-measure); margin-inline: auto; }

.lm-tick {
  width: 2.6rem; height: 2.6rem;
  margin-bottom: 1.5rem;
  border-radius: 50%;
  background: var(--lm-positive);
  display: grid;
  place-items: center;
}
.lm-tick::after {
  content: "";
  width: 0.85rem; height: 0.45rem;
  margin-top: -0.2rem;
  border-left: 2.5px solid var(--lm-ground);
  border-bottom: 2.5px solid var(--lm-ground);
  transform: rotate(-45deg);
}

.lm-thanks h1 { font-size: clamp(1.75rem, 1.3rem + 2.2vw, 2.5rem); }
.lm-thanks-body { margin: 1rem 0 0; font-size: var(--fs-lead); color: var(--lm-muted); text-wrap: pretty; }
.lm-thanks-body p { margin: 0 0 0.9em; }
.lm-thanks-body > :last-child { margin-bottom: 0; }

.lm-primary { margin-top: 2rem; }
.lm-primary .lm-btn { font-size: var(--fs-lead); padding: 1rem 1.75rem; }

.lm-opened {
  margin: 0.85rem 0 0;
  font-size: var(--fs-small);
  color: var(--lm-muted);
}

/* 16:9 without an aspect-ratio fallback, because every browser that can run
   this page has had it since 2021. */
.lm-video { margin-top: 2.25rem; }
.lm-video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  overflow: hidden;
  background: var(--lm-surface);
  border: 1px solid var(--lm-rule);
}
.lm-video-frame iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
}

.lm-next {
  margin-top: 2.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--lm-rule);
  font-size: var(--fs-small);
  color: var(--lm-muted);
}

@media (prefers-reduced-motion: no-preference) {
  .lm-thanks { animation: lm-rise 320ms var(--lm-ease) both; }
  @keyframes lm-rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ── the framework document ────────────────────────────────────────────────
   /assets/<slug>/. A landing page is read in one glance; this is read for four
   minutes, so the measure is wider, the rhythm is looser, and the headings
   carry a rule rather than just size. */

.lm-doc { max-width: 42rem; }
.lm-doc .lm-headline { font-size: clamp(1.9rem, 1.3rem + 2.6vw, 2.75rem); }
.lm-doc .lm-body { margin-top: 2.5rem; }

.lm-doc .lm-body h2 {
  margin: 3rem 0 1rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--lm-rule);
  font-size: clamp(1.2rem, 1.05rem + 0.7vw, 1.45rem);
  letter-spacing: 0.01em;
  text-transform: lowercase;
  color: var(--lm-muted);
}
.lm-doc .lm-body h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.lm-doc .lm-body h3 { margin: 2rem 0 0.6rem; font-size: 1.1rem; }
.lm-doc .lm-body p { margin: 0 0 1.25em; }

/* A document's bullets are NOT a tick list. On a landing page every bullet is
   something you get, so a green tick is the honest mark. In a framework the
   same mark landed on "Never: use AI to make thumbnails" and read as approval
   of the thing being forbidden. Neutral marks here: a rule at the first level,
   a dot at the second. */
.lm-doc .lm-body ul li::before {
  border: 0;
  transform: none;
  top: 0.82em;
  left: 0.1rem;
  width: 0.7rem;
  height: 2px;
  background: var(--lm-line);
}
.lm-doc .lm-body ul ul { margin: 0.7rem 0 0.2rem; }
.lm-doc .lm-body ul ul li::before {
  border: 0;
  width: 0.45rem; height: 0.45rem;
  top: 0.62em; left: 0.3rem;
  border-radius: 50%;
  background: var(--lm-line);
  transform: none;
}

.lm-figure { margin: 2rem 0; }
.lm-figure img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--lm-rule);
  border-radius: 10px;
}
.lm-figure figcaption {
  margin-top: 0.7rem;
  font-size: var(--fs-small);
  color: var(--lm-muted);
  text-wrap: pretty;
}

/* ── the locked state: what a stranger sees ───────────────────────────────── */

.lm-locked {
  margin-top: 2.5rem;
  padding: 2rem 1.5rem;
  background: var(--lm-surface);
  border: 1px solid var(--lm-rule);
  border-radius: 12px;
}
.lm-locked p { margin: 0 0 1em; color: var(--lm-muted); }
.lm-locked-head { font-size: var(--fs-lead); color: var(--lm-ink) !important; font-weight: 700; }
.lm-locked p:last-child { margin-bottom: 0; }

/* The download. One button, at the top of the document, because someone who
   came here from an email came for the file and should not have to read to the
   end to find it. Inside the body rather than the template, so Ghost's member
   gate covers the URL. */
.lm-dl { margin: 0 0 2.25rem; }
.lm-dl .lm-btn { font-size: var(--fs-small); padding: 0.6rem 1.1rem; }

/* ── the homepage ──────────────────────────────────────────────────────────
   One line and a form. The line is set at heading weight rather than heading
   size: it is a sentence, and a sentence set at 3rem is a slogan. */

.lm-home { max-width: 34rem; padding-top: clamp(4rem, 18vh, 9rem); }
.lm-lede {
  margin: 0 0 2.5rem;
  font-size: clamp(1.25rem, 1.05rem + 1vw, 1.6rem);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.015em;
  text-wrap: pretty;
}

/* ── the signup form, and its three screens ────────────────────────────────
   Every form on the site is this one: the homepage, a post, a lead magnet.
   `.lm-state` is what a submit swaps the form for — replacing rather than
   appending, because a confirmation that renders below the fold is a
   confirmation nobody reads. */

.lm-signup [hidden] { display: none !important; }

.lm-state {
  animation: lm-rise 320ms var(--lm-ease) both;
}
.lm-state h2 {
  margin: 0 0 0.5rem;
  font-size: clamp(1.3rem, 1.1rem + 1vw, 1.75rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.lm-state p { margin: 0; color: var(--lm-muted); text-wrap: pretty; }
.lm-state .lm-tick { margin-bottom: 1.1rem; }

@media (prefers-reduced-motion: reduce) {
  .lm-state { animation: none; }
}

/* A post's form has to introduce itself: it arrives after a thousand words
   about something else. The homepage's does not — there, it IS the page. */
.lm-signup-block {
  max-width: var(--measure);
  margin: 3.5rem 0 0;
  padding: 1.75rem;
  background: var(--s-surface);
  border: 1px solid var(--s-rule);
  border-radius: 12px;
}
.lm-signup-block h2 { margin: 0 0 0.4rem; font-size: 1.3rem; font-weight: 800; }
.lm-signup-block > p { margin: 0 0 1.1rem; color: var(--s-ink-muted); }

/* Scoped tokens, so the form works outside a `.lm` page — a post is rendered
   by `default`, which has no `.lm` wrapper for the variables to come from. */
.lm-signup-block, .lm-signup {
  --lm-ink: var(--s-ink);        --lm-muted: var(--s-ink-muted);
  --lm-mark: var(--s-ink);       --lm-on-mark: var(--s-paper);
  --lm-field: var(--s-paper);    --lm-line: var(--s-line);
  --lm-negative: var(--s-negative);
  --lm-positive: var(--s-positive);
  --lm-ease: var(--ease);
  --fs-small: 0.875rem;          --fs-lead: 1.125rem;
}
