/* ═══════════════════════════════════════════════════════════════════════════════
   monitorMyLawn — /pricing + /about page compositions.
   Loaded as $pageCss = ['marketing', 'commerce-pages'].

   assets/css/marketing.css is the design system and it is NOT owned here. Anything
   in this file is a composition that exists on exactly these two pages; everything
   reusable (.plate, .hairgrid, .statband, .accordion, .callout, .toolindex__list,
   .specgrid, .vizframe, .scroller, .pullquote, .bignum, .chip…) is used straight
   from marketing.css rather than re-cut here.

   Tokens only. No hex literal may appear in this file — add it to tokens.css.

   ─────────────────────────────────────────────────────────────────────────────
   INDEX
     .plans / .plan (+ --best) / .plan__term .plan__amt .plan__n .plan__u
                              — the two subscription plates on /pricing
     .receipts / .receipt / .receipt__h .receipt__n .receipt__sub
                .receipt__l .receipt__f
                              — the 1 / 2 / 4 sensor worked example
     .qtyfig                  — SVG classes for the billed-quantity step figure
     .erratum                 — the 2.5x ET0 unit bug figure on /about
     .cp-rise                 — CSS-only scroll entrance. No JS anywhere on these
                                two pages, so this is scroll-timeline driven and
                                simply does not apply where that is unsupported.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ═══ .hairgrid, MULTI-ROW — left-column alignment ════════════════════════════
   marketing.css zeroes the left padding on `:first-child` only. That is right for a
   single-row rail (the homepage and the footer both use one), but /pricing runs an
   eight-item --2 grid: every left-column cell BELOW the first then sits var(--sp-lg)
   in and stops lining up with the section heading and the caption above and below it.
   Zeroing per column instead is the same intent, generalised. Scoped to this sheet so
   it cannot disturb the pages Track S owns — reported for the system in "handoff". */
@media (min-width: 680px) {
  .hairgrid--2 > :nth-child(2n+1),
  .hairgrid--3 > :nth-child(2n+1),
  .hairgrid--4 > :nth-child(2n+1) { padding-left: 0; }
}
@media (min-width: 1000px) {
  /* --3/--4/--5 change column count here, so the two-column rule above has to be
     undone before the real first column is zeroed. Order matters: equal specificity. */
  .hairgrid--3 > :nth-child(2n+1),
  .hairgrid--4 > :nth-child(2n+1) { padding-left: var(--sp-lg); }
  .hairgrid--3 > :nth-child(3n+1),
  .hairgrid--4 > :nth-child(4n+1),
  .hairgrid--5 > :nth-child(5n+1) { padding-left: 0; }
}

/* ═══ .spec-tbc — AA repair for the UNCONFIRMED chip ══════════════════════════
   marketing.css paints .spec-tbc in --mml-viz-warn over its own 8% amber tint. That
   token is measured against an OPAQUE surface (5.02:1); once its own tint and then a
   .callout--warn's 9% amber stack underneath, the light-theme ink measures 4.40:1 on
   --mml-bg and 4.15:1 inside the callout — both under AA for 11px/700 text. Putting an
   opaque surface back under the chip restores the token's measured pair (5.02:1 light,
   9.65:1 dark) and, if anything, makes the blank field louder, which is its whole job.
   Reported for the system copy in "handoff". */
.spec-tbc { background: var(--mml-surface); }

/* ═══ PLAN PLATES (/pricing) ══════════════════════════════════════════════════
   Deliberately NOT .pricepreview — that one lives in the homepage-specific block
   of marketing.css and carries only a price and a sentence. These hold a price,
   a measured unit rate, a two-row .specgrid and an action. */
.plans {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-lg);
  margin-top: var(--sp-2xl);
}
@media (min-width: 780px) { .plans { grid-template-columns: 1fr 1fr; gap: var(--sp-xl); } }

.plan {
  position: relative; display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--mml-border); border-radius: var(--r-xl);
  background: var(--mml-surface); padding: var(--sp-xl);
  box-shadow: var(--shadow-sm);
}
.plan--best {
  border-color: rgba(var(--mml-primary-rgb), .5);
  box-shadow: var(--shadow-md), 0 0 0 4px rgba(var(--mml-primary-rgb), .07);
}
.plan__term {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-md); flex-wrap: wrap;
  font-family: var(--font-mono); font-size: .66rem; letter-spacing: .14em;
  text-transform: uppercase; font-weight: 700; color: var(--mml-text-3);
  margin-bottom: var(--sp-md);
}
.plan__amt { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; margin-bottom: var(--sp-lg); }
.plan__n {
  font-size: clamp(2.4rem, 1.85rem + 2.1vw, 3.15rem); font-weight: 800;
  letter-spacing: -.04em; line-height: 1; color: var(--mml-text);
  font-variant-numeric: tabular-nums;
}
.plan__u {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; font-weight: 700; color: var(--mml-text-3);
}
.plan .specgrid { margin-bottom: var(--sp-lg); }
.plan__note { font-size: .88rem; color: var(--mml-text-2); line-height: 1.6; margin: 0 0 var(--sp-xl); }
/* margin-top:auto pins the action to the bottom so both plates align however
   long the notes run. */
.plan > .btn { margin-top: auto; justify-content: center; }

/* ═══ WORKED EXAMPLE — THREE RECEIPTS (/pricing) ══════════════════════════════
   A .cmp table would have needed a 620px min-width and a horizontal scroller for
   what is really three independent little ledgers. These stack instead. */
.receipts { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-lg); }
@media (min-width: 900px) { .receipts { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.receipt {
  display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--mml-border); border-radius: var(--r-xl);
  background: var(--mml-surface); padding: var(--sp-lg);
  box-shadow: var(--shadow-xs);
}
.receipt__h { display: flex; align-items: baseline; gap: .6rem; }
.receipt__n {
  font-family: var(--font-mono); font-size: .72rem; font-weight: 800;
  letter-spacing: .1em; color: var(--mml-link); flex: none;
}
.receipt__h h3 { margin: 0; font-size: 1.02rem; letter-spacing: -.02em; }
.receipt__sub { font-size: .8rem; color: var(--mml-text-3); line-height: 1.5; margin: .3rem 0 var(--sp-lg); }
.receipt__l {
  font-family: var(--font-mono); font-size: .78rem; line-height: 1.95;
  color: var(--mml-text-2); font-variant-numeric: tabular-nums; margin: 0;
}
.receipt__l div { display: flex; justify-content: space-between; gap: var(--sp-md); min-width: 0; }
.receipt__l span:first-child { min-width: 0; overflow-wrap: anywhere; }
.receipt__l b { color: var(--mml-text); font-weight: 650; white-space: nowrap; flex: none; }
.receipt__l .tot { border-top: 1.5px solid var(--mml-rule-strong); margin-top: .4rem; padding-top: .4rem; }
.receipt__l .tot b { color: var(--mml-link); font-weight: 800; font-size: .92rem; }
.receipt__f {
  margin-top: auto; padding-top: var(--sp-md);
  font-size: .78rem; color: var(--mml-text-3); line-height: 1.5;
}

/* ═══ BILLED-QUANTITY STEP FIGURE (/pricing) ══════════════════════════════════
   The whole point of per-device billing is that the invoice quantity is just a
   count of switched-on sensors, so it gets drawn rather than described. Sits in a
   .vizframe > .scroller; the SVG keeps a min-width so the labels stay legible on
   a phone instead of shrinking to nothing. */
.qtyfig { min-width: 640px; }
.qtyfig text { font-family: var(--font-mono); }
.qtyfig .ax    { fill: var(--mml-text-3); font-size: 19px; font-weight: 700; letter-spacing: .08em; }
.qtyfig .mon   { fill: var(--mml-text-2); font-size: 18px; font-weight: 700; letter-spacing: .1em; }
.qtyfig .amt   { fill: var(--mml-text); font-size: 22px; font-weight: 700; letter-spacing: -.01em; }
.qtyfig .note  { fill: var(--mml-text-2); font-size: 18px; }
.qtyfig .warn  { fill: var(--mml-viz-warn); font-size: 18px; font-weight: 700; }
.qtyfig .rule      { stroke: var(--mml-rule); stroke-width: 1; }
.qtyfig .rule--ax  { stroke: var(--mml-rule-strong); stroke-width: 1.5; }
.qtyfig .band  { fill: rgba(var(--mml-primary-rgb), .11); }
.qtyfig .step  { fill: none; stroke: var(--mml-primary); stroke-width: 3.4; stroke-linejoin: round; stroke-linecap: round; }
.qtyfig .knot  { fill: var(--mml-surface); stroke: var(--mml-primary); stroke-width: 3; }
.qtyfig .evt   { stroke: var(--mml-viz-warn); stroke-width: 1.6; stroke-dasharray: 5 4; }
.qtyfig .chip  { fill: var(--mml-surface-hover); stroke: var(--mml-rule-strong); stroke-width: 1; }

/* ═══ /ABOUT ══════════════════════════════════════════════════════════════════ */

/* The ET0 unit bug. A ratio, not a measurement — the only figure the copy states
   is "roughly two and a half times", so that is the only figure drawn. */
.erratum { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-lg); align-items: center; }
@media (min-width: 700px) { .erratum { grid-template-columns: 178px minmax(0, 1fr); gap: var(--sp-2xl); } }
.erratum__fig { text-align: center; }
.erratum__fig .bignum { display: block; }
.erratum__fig figcaption {
  font-family: var(--font-mono); font-size: .58rem; letter-spacing: .13em;
  text-transform: uppercase; font-weight: 700; color: var(--mml-text-3);
  margin-top: var(--sp-sm); line-height: 1.5;
}
.erratum p:last-child { margin-bottom: 0; }

/* The five "we do not" commitments reuse .toolindex__list / __i / __n from
   marketing.css. On the homepage that list sits in a 1fr column beside a 300px sticky
   plate; here it has the whole 1080px plate body, and an unconstrained line ran to
   ~100 characters. Cap the measure, keep the hairlines full width. */
.nots .toolindex__i h3 { font-size: 1rem; }
.nots .toolindex__i > div > p { max-width: 74ch; margin-bottom: 0; }

/* ═══ MOTION ══════════════════════════════════════════════════════════════════
   marketing.css's .reveal needs assets/js/home.js to add .is-in, and neither of
   these pages loads any JavaScript — a bare .reveal here would sit at opacity 0
   forever. So .cp-rise is the JS-free stand-in.

   It is deliberately TIME-based rather than scroll-driven. This was first built with
   `animation-timeline: view()`, which is the prettier answer — but that reveal holds
   its from-keyframe (opacity 0) until the subject reaches its range, so a range that
   is wrong for some viewport does not degrade, it deletes the copy. Nobody could
   observe that here to rule it out: the QA browser runs with prefers-reduced-motion
   on and drives a background tab, where the animation clock is frozen and a view()
   timeline never reports active. An unverifiable way to blank a pricing page is not
   a trade worth taking for a fade.

   A plain duration has no geometry to get wrong. `both` fill puts every element on
   the end keyframe 0.62 s after load whether it has been scrolled to or not — checked
   by driving the animation by hand through the Web Animations API: 0 at t=0, 0.8 at
   t=310ms, 1 at t=620ms and still 1 at t=5s, on all 13 subjects. Under reduce the
   block does not apply at all (computed animation-name is `none`) AND base.css
   independently clamps every animation-duration to .001ms, so the page is complete
   on first paint. */
@media (prefers-reduced-motion: no-preference) {
  .cp-rise { animation: cp-rise .62s cubic-bezier(.2, .7, .3, 1) both; }
  .cp-rise[data-d="1"] { animation-delay: .08s; }
  .cp-rise[data-d="2"] { animation-delay: .16s; }
  .cp-rise[data-d="3"] { animation-delay: .24s; }
  @keyframes cp-rise {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
  }
}
