/* ============================================================================
   La Soglia — the Money Mastery design system.

   One sheet for the pricing page, the four plan pages, the features hub and
   the five module pages. Twelve pages that used to be twelve copies of the
   same 400 lines, which is how a palette drifts: someone fixes a contrast bug
   on one page and the other eleven keep the old value.

   PALETTE, AND WHY IT IS NOT THE BRAND DECK'S PALETTE VERBATIM
   The deck specifies terracotta #C56B4A as the accent. White on it measures
   3.77 and terracotta text on the cream ground measures 3.62, both below the
   4.5 that normal text needs. So terracotta is kept as a NON-TEXT mark only —
   rules, dots, underlines, the little bar above a heading — and clay #A8563B
   carries every link, button and label. White on clay is 5.17. Clay on ground
   is 4.97.

   EVERY HOVER DARKENS to --clay-deep #9E4F35. Lightening a hover is what
   produced the 3.77 in the first place.

   THE CASCADE TRAP, which has shipped on this site four times:
   `.btn` is usually an <a>, so a bare `a:hover` (0,1,1) outranks `.btn`
   (0,1,0) and repaints the label to match its own hover background. Ratio
   1.00, an invisible button. Every hover rule below restates `color`, and any
   scoped link rule uses `:not(.btn)`. Do not remove either.
   ========================================================================= */

:root {
  /* ground and paper */
  --ground:#FDFAF5;    /* page */
  --wash:#FAF3EC;      /* hover fill, quiet panel */
  --sand:#EFE7DC;      /* solid panel */
  --rule:#E2D6C4;      /* hairline */
  --white:#FFFFFF;

  /* ink */
  --ink:#3D3330;       /* headings, 11.8 on ground */
  --body:#574C46;      /* body, 7.98 on ground */
  --muted:#6B5D54;     /* secondary, 5.55 on ground */

  /* accent */
  --clay:#A8563B;      /* every action. 4.97 on ground, white on it 5.17 */
  --clay-deep:#9E4F35; /* every hover. never lighter */
  --clay-dark:#8E4730; /* on sand and wash */
  --terracotta:#C56B4A;/* NON-TEXT ONLY. 3.62 as text, fails AA */
  --clay-wash:rgba(168,86,59,.09);

  --ok:#4A574E;
  --warn:#8C3A2A;

  --display:'Playfair Display', Georgia, 'Times New Roman', serif;
  --sans:'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --ease:cubic-bezier(.22,.61,.36,1);
  --spring:cubic-bezier(.34,1.4,.64,1);

  /* a 1.25 scale, clamped so nothing needs a breakpoint to be readable */
  --t-hero:clamp(38px,6.6vw,74px);
  --t-h1:clamp(32px,5vw,54px);
  --t-h2:clamp(25px,3.4vw,38px);
  --t-h3:clamp(19px,2vw,23px);
  --t-lead:clamp(17px,1.9vw,20px);
  --t-body:16px;
  --t-small:14px;
  --t-fine:12.5px;
  --t-label:11px;

  --gap:clamp(20px,4vw,40px);
  --section:clamp(56px,9vw,116px);
  --shell:1180px;

  /* Measured, not guessed: the sticky header is 69px once the webfont lands,
     and 82px below 780px where the nav wraps. Anything that sticks under it
     offsets by this. */
  --top-h:70px;
}
@media(max-width:780px){:root{--top-h:84px}}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  font-family:var(--sans);font-size:var(--t-body);line-height:1.7;
  background:var(--ground);color:var(--body);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img,svg{max-width:100%;display:block}

h1,h2,h3,h4{font-family:var(--display);color:var(--ink);font-weight:500;line-height:1.08}
h1{font-size:var(--t-h1);letter-spacing:-.021em;text-wrap:balance}
h2{font-size:var(--t-h2);letter-spacing:-.016em;text-wrap:balance}
h3{font-size:var(--t-h3);letter-spacing:-.008em;line-height:1.24}
h4{font-size:17px;letter-spacing:-.004em}
p{max-width:66ch}
strong,b{font-weight:600;color:var(--ink)}
em{font-style:italic}

a{color:var(--clay);text-decoration-thickness:1px;text-underline-offset:.2em;
  transition:color .22s var(--ease)}
a:hover{color:var(--clay-deep)}
:focus-visible{outline:2px solid var(--clay);outline-offset:3px;border-radius:2px}
::selection{background:rgba(168,86,59,.15);color:var(--ink)}

/* ── layout ────────────────────────────────────────────────────────────── */
.shell{width:100%;max-width:var(--shell);margin-inline:auto;
       padding-inline:clamp(20px,5vw,48px)}
.shell--narrow{max-width:820px}
.section{padding-block:var(--section)}
.section--tight{padding-block:clamp(40px,6vw,72px)}
.section--sand{background:var(--sand)}
.section--wash{background:var(--wash)}
.hr{border:0;border-top:1px solid var(--rule)}

.eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.19em;
         text-transform:uppercase;color:var(--muted);display:block}
.mark-rule{width:44px;height:2px;background:var(--terracotta);border:0;margin-bottom:22px}
.lead{font-size:var(--t-lead);line-height:1.62;color:var(--body);max-width:58ch}
/* The line under a Join button while checkout opens, and if it does not.
   Sized at 15px rather than --t-fine because the reader it matters most to is
   the one whose payment just failed, and 12.5px is the wrong size for that
   sentence. See js/mm-checkout.js. */
.buy-msg{margin:10px 0 0;font-size:15px;line-height:1.6;color:var(--body);max-width:56ch}
.buy-msg:empty{margin:0}
[data-buy][aria-disabled="true"]{opacity:.72;pointer-events:none}

.fine{font-size:var(--t-fine);color:var(--muted);line-height:1.6}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.center{text-align:center}
.center p,.center .lead{margin-inline:auto}

/* ── header ────────────────────────────────────────────────────────────── */
.top{position:sticky;top:0;z-index:80;background:rgba(253,250,245,.88);
     backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
     border-bottom:1px solid transparent;transition:border-color .3s var(--ease)}
.top.is-stuck{border-bottom-color:var(--rule)}
.top .shell{display:flex;align-items:center;justify-content:space-between;
            gap:24px;padding-block:15px}
.wordmark{font-family:var(--display);font-size:16.5px;font-weight:600;
          color:var(--ink);text-decoration:none;letter-spacing:.01em;white-space:nowrap;
          display:block;line-height:1.1}
.wordmark span{color:var(--clay)}
.wordmark small{display:block;font-family:var(--sans);font-size:9px;font-weight:600;
                letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
                margin-top:3px}

/* ── navigation ─────────────────────────────────────────────────────────── */
.nav{display:flex;align-items:center;gap:clamp(4px,1.4vw,10px);font-size:14px}
.nav-item{position:relative}
.nav-btn{display:inline-flex;align-items:center;gap:.4em;font:inherit;font-size:14px;
  color:var(--muted);background:none;border:0;cursor:pointer;padding:9px 11px;
  border-radius:2px;transition:color .2s var(--ease),background-color .2s var(--ease)}
.nav-btn:hover,.nav-btn[aria-expanded="true"]{color:var(--ink);background:var(--wash)}
.nav-btn .chev{width:8px;height:8px;border-right:1.4px solid currentColor;
  border-bottom:1.4px solid currentColor;transform:rotate(45deg) translate(-1px,-1px);
  transition:transform .24s var(--ease)}
.nav-btn[aria-expanded="true"] .chev{transform:rotate(-135deg) translate(-2px,-2px)}
.nav a:not(.btn){color:var(--muted);text-decoration:none;padding:9px 11px;border-radius:2px;
  transition:color .2s var(--ease),background-color .2s var(--ease)}
.nav a:not(.btn):hover{color:var(--ink);background:var(--wash)}
.nav a:not(.btn)[aria-current="page"]{color:var(--ink)}

.menu{position:absolute;top:calc(100% + 8px);right:0;left:auto;z-index:90;min-width:288px;
  background:var(--white);border:1px solid var(--rule);border-radius:3px;
  box-shadow:0 22px 48px -26px rgba(61,51,48,.42);padding:10px;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .22s var(--ease),transform .22s var(--ease),visibility .22s}
.menu[data-open="true"]{opacity:1;visibility:visible;transform:none}
.menu--wide{min-width:min(560px,calc(100vw - 40px));display:grid;
  grid-template-columns:1fr 1fr;gap:2px}
.menu-h{font-size:var(--t-label);font-weight:600;letter-spacing:.15em;
  text-transform:uppercase;color:var(--muted);padding:10px 12px 6px;grid-column:1/-1}
.menu--wide .menu-h + .menu-a{grid-column:auto}
.menu-a{display:block;padding:9px 12px;border-radius:2px;text-decoration:none;
  color:var(--ink);font-size:14px;line-height:1.35;
  transition:background-color .18s var(--ease),color .18s var(--ease)}
.menu-a small{display:block;font-size:12px;color:var(--muted);margin-top:2px}
.menu-a:hover{background:var(--wash);color:var(--clay-deep)}
.menu-a:hover small{color:var(--muted)}
.menu-sep{grid-column:1/-1;height:1px;background:var(--rule);margin:8px 4px}

/* the mobile sheet */
.nav-burger{display:none;font:inherit;background:none;border:1px solid var(--rule);
  border-radius:2px;padding:9px 12px;color:var(--ink);cursor:pointer;font-size:13.5px;
  align-items:center;gap:.5em}
.nav-burger:hover{background:var(--wash)}
.sheet{position:fixed;inset:0;z-index:200;background:rgba(61,51,48,.34);
  overflow:hidden;
  opacity:0;visibility:hidden;transition:opacity .28s var(--ease),visibility .28s}
.sheet[data-open="true"]{opacity:1;visibility:visible}
.sheet-panel{position:absolute;top:0;right:0;bottom:0;width:min(400px,88vw);
  background:var(--ground);overflow-y:auto;padding:18px 18px 40px;
  transform:translateX(100%);transition:transform .32s var(--ease);
  -webkit-overflow-scrolling:touch}
.sheet[data-open="true"] .sheet-panel{transform:none}
.sheet-top{display:flex;align-items:center;justify-content:space-between;
  padding-bottom:14px;border-bottom:1px solid var(--rule);margin-bottom:8px}
.sheet-x{font:inherit;font-size:22px;line-height:1;background:none;border:0;
  color:var(--muted);cursor:pointer;padding:6px 10px;border-radius:2px}
.sheet-x:hover{background:var(--sand);color:var(--ink)}
.sheet h4{font-family:var(--sans);font-size:var(--t-label);font-weight:600;
  letter-spacing:.15em;text-transform:uppercase;color:var(--muted);
  margin:18px 0 4px;padding-inline:6px}
.sheet a{display:block;padding:10px 6px;text-decoration:none;color:var(--ink);
  font-size:15px;border-bottom:1px solid var(--rule)}
.sheet a:last-child{border-bottom:0}
.sheet a:hover{color:var(--clay-deep)}
.sheet a small{display:block;font-size:12.5px;color:var(--muted);margin-top:2px}
.sheet .btn{width:100%;margin-top:18px}

/* display:contents so the three .nav-item children lay out as direct flex
   children of .nav. This lives here rather than inline: an inline style beats
   a media query, so the inline version could not be switched off on mobile
   and the dropdowns stayed on screen next to the burger. */
.nav-desktop{display:contents}

/* Hover belongs in CSS. As JS mouseenter/mouseleave it fought the click
   handler: hovering opened the menu, then the click read it as open and shut
   it. Here it cannot, because it never touches aria-expanded. */
@media(hover:hover) and (min-width:901px){
  .nav-item:hover .menu{opacity:1;visibility:visible;transform:none}
  .nav-item:hover .nav-btn{color:var(--ink);background:var(--wash)}
  .nav-item:hover .nav-btn .chev{transform:rotate(-135deg) translate(-2px,-2px)}
}

@media(max-width:900px){
  .nav-desktop{display:none}
  .nav-burger{display:inline-flex}
}

/* ── buttons ───────────────────────────────────────────────────────────── */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.55em;
     font-family:var(--sans);font-size:14.5px;font-weight:600;letter-spacing:.025em;
     line-height:1;padding:15px 28px;border:1px solid transparent;border-radius:2px;
     background:var(--clay);color:var(--white);cursor:pointer;text-decoration:none;
     transition:background-color .26s var(--ease),transform .26s var(--spring),
                border-color .26s var(--ease),color .26s var(--ease)}
/* colour restated. See the cascade note at the top of this file. */
.btn:hover{background:var(--clay-deep);color:var(--white);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn[aria-disabled="true"],.btn:disabled{background:var(--muted);cursor:default;transform:none}
.btn--lg{padding:18px 34px;font-size:15.5px}
.btn--sm{padding:11px 19px;font-size:13.5px}
/* A coarse pointer gets a real tap target. Measured on a touch emulation, not
   assumed: .btn--sm renders at 38px, which passes a glance and fails a thumb.
   Scoped to pointer:coarse so nothing about the desktop rendering changes, and
   only ever increases height -- the buttons are inline-flex with centred
   items, so the label stays put. */
@media (pointer: coarse) {
  /* A FLOOR FOR EVERY BUTTON, not just the small one. The narrow-width rule
     further down re-pads .btn--lg to 16px, and on a 390px screen that measured
     36px tall on /pricing: under the 44px minimum, on a PAYMENT button, for an
     audience the owner describes as women 40 to 60. Caught by the buy-button
     test, not by looking at it, which is the argument for the test.
     48px rather than 44 for the same reason the walkthrough uses 48. */
  .btn, .btn--lg, .btn--sm { min-height: 48px; }
  .btn--sm { min-height: 44px; }
}
.btn--full{width:100%}
.btn--ghost{background:transparent;color:var(--clay);border-color:var(--rule)}
.btn--ghost:hover{background:var(--wash);color:var(--clay-deep);border-color:var(--clay)}
.btn--onclay{background:var(--white);color:var(--clay);border-color:var(--white)}
.btn--onclay:hover{background:var(--wash);color:var(--clay-deep);border-color:var(--wash)}
.btn .arw{transition:transform .26s var(--ease)}
.btn:hover .arw{transform:translateX(3px)}

/* ── panels and cards ──────────────────────────────────────────────────── */
.card{background:var(--white);border:1px solid var(--rule);border-radius:3px;
      padding:clamp(22px,3vw,30px)}
.card--link{text-decoration:none;color:inherit;display:block;
            transition:border-color .3s var(--ease),transform .3s var(--ease),
                       box-shadow .3s var(--ease)}
.card--link:hover{border-color:var(--clay);transform:translateY(-3px);
                  box-shadow:0 18px 40px -26px rgba(61,51,48,.4)}
.card--link:hover .go{color:var(--clay-deep)}
.card--link:hover .arw{transform:translateX(4px)}
.card h3{margin-bottom:9px}
.card p{font-size:15px;margin:0}
.go{display:inline-flex;align-items:center;gap:.5em;margin-top:16px;
    font-size:var(--t-label);font-weight:600;letter-spacing:.11em;
    text-transform:uppercase;color:var(--clay)}
/* :not(.btn) is load-bearing. A bare `.panel a` (0,1,1) outranks `.btn`
   (0,1,0) and repaints a button's own label. Ratio 1.09, invisible. */
.panel{background:var(--sand);border-radius:3px;padding:clamp(24px,4vw,38px)}
/* Clay measures 4.22 against --sand and fails AA. --clay-dark is 5.54. This
   applies to the sand SECTION too, not just .panel, because a link in a
   section body sits on exactly the same ground. :not(.btn) throughout, or
   these repaint a button's own label. */
.panel a:not(.btn),
.section--sand a:not(.btn){color:var(--clay-dark)}
.panel a:not(.btn):hover,
.section--sand a:not(.btn):hover{color:#7F3F2B}
.section--sand .btn--ghost{color:var(--clay-dark);border-color:var(--rule)}
.section--sand .btn--ghost:hover{background:var(--white);color:#7F3F2B;border-color:var(--clay)}

.grid{display:grid;gap:var(--gap)}
.grid--2{grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
.grid--3{grid-template-columns:repeat(auto-fit,minmax(min(100%,268px),1fr))}
.grid--split{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:start}
@media(max-width:860px){.grid--split{grid-template-columns:minmax(0,1fr)}}

/* ── the ledger list: hairline rows, right-aligned figures ─────────────── */
.ledger{list-style:none}
.ledger li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:16px;
           align-items:baseline;padding-block:13px;border-bottom:1px solid var(--rule);
           font-size:15px;color:var(--ink)}
.ledger li:first-child{border-top:1px solid var(--rule)}
.ledger li span{font-size:var(--t-small);color:var(--muted)}
/* Not a grid. A grid row here counts its items, and an <li> whose text starts
   with <strong> produces THREE items (the dot, the strong, the trailing text)
   rather than two, so the text wrapped into the dot's column, the 1fr column
   collapsed to 0px, and the row measured 401px inside a 335px box. Padding
   plus an absolutely positioned dot cannot miscount, whatever the markup. */
.ledger--plain li{display:block;position:relative;padding-left:18px;
                  grid-template-columns:none;align-items:initial}
/* top is measured from the LI's PADDING box, and .ledger li carries
   padding-block:13px -- so `top:.62em` put the dot 13px above the line it
   was marking. At 15px/1.7 the first line's centre is 25.75px down and the
   dot sat at 9.3px: a 16px error, plainly visible on a phone, and the whole
   of "bullets don't align". The centre of the first line is
   padding-top + (line-box / 2), minus half the dot. */
.ledger--plain li::before{content:'';position:absolute;left:1px;top:calc(13px + .68em);
  width:5px;height:5px;border-radius:50%;background:var(--terracotta)}

/* The calc above hard-codes the line-height the dot is centring against.
   Where `lh` exists the browser can measure the real line box, so the dot
   stays centred if the type scale ever moves. Chrome 109, Safari 16.4,
   Firefox 120 -- older engines keep the calc, which is correct today. */
@supports (top: 1lh) {
  .ledger--plain li::before{top:calc(13px + (1lh - 5px) / 2)}
  .tier li::before{top:calc(7px + (1lh - 5px) / 2)}
}

/* ══════════════════════════════════════════════════════════════════════════
   ROWS THAT FILL

   Every card grid here was `repeat(auto-fit, minmax(N, 1fr))`, which packs in
   as many columns as happen to fit and then leaves the last row short. Five
   workbook cards at three columns is 3 + 2 with a third of the row empty
   beside the last two; four tiers at 1000px is 3 + 1, with one tier stranded
   on its own line looking like an afterthought rather than a peer.

   The fix is to stop letting the width choose the column count and let the
   ITEM COUNT choose it, picking only counts the items divide into evenly.

   `:has(> :nth-child(N):last-child)` is a quantity query: it matches a grid
   with exactly N children. So a six-card grid asks for 3 / 2 / 1 columns and a
   four-card grid asks for 4 / 2 / 1, and every row in both is full at every
   width. Wrapped in @supports so a browser without :has() keeps the old
   auto-fit behaviour rather than losing its layout -- Chrome 105, Safari 15.4
   and Firefox 121 all have it.

   FIVE is the one count that divides into nothing. It gets a six-track grid:
   three cards spanning two tracks each, then two spanning three each. Both
   rows are completely full, which is the thing being asked for, and no card
   is left at a third-width beside a gap.
   ══════════════════════════════════════════════════════════════════════════ */
@supports selector(:has(*)) {

  /* Each width band is a SEPARATE query with no overlap, and every rule lives
     in exactly one of them. The first version of this block put the wide rules
     at the top and overrode them lower down, and lost: `> :nth-child(n+4)` is
     more specific than `> *`, so the five-card spans survived into the
     two-column band and forced a phantom third track. Non-overlapping bands
     mean there is nothing to out-specify. */

  /* ── wide: 1001px and up ─────────────────────────────────────────────── */
  @media (min-width:1001px){
    .grid--2:has(> :nth-child(2):last-child),
    .grid--3:has(> :nth-child(2):last-child),
    .tiers:has(> :nth-child(2):last-child){grid-template-columns:repeat(2,1fr)}

    /* three never takes two columns: that is 2 + 1 */
    .grid--2:has(> :nth-child(3):last-child),
    .grid--3:has(> :nth-child(3):last-child),
    .tiers:has(> :nth-child(3):last-child),
    .mm-quotes:has(> :nth-child(3):last-child){grid-template-columns:repeat(3,1fr)}

    .grid--2:has(> :nth-child(4):last-child),
    .grid--3:has(> :nth-child(4):last-child),
    .tiers:has(> :nth-child(4):last-child),
    .stats:has(> :nth-child(4):last-child){grid-template-columns:repeat(4,1fr)}

    .grid--2:has(> :nth-child(6):last-child),
    .grid--3:has(> :nth-child(6):last-child),
    .tiers:has(> :nth-child(6):last-child){grid-template-columns:repeat(3,1fr)}

    /* FIVE is the count that divides into nothing. Six tracks: three cards
       spanning two each, then two spanning three each. Both rows completely
       full, and no card left at a third-width beside a gap. */
    .grid--2:has(> :nth-child(5):last-child),
    .grid--3:has(> :nth-child(5):last-child),
    .tiers:has(> :nth-child(5):last-child),
    .stats:has(> :nth-child(5):last-child){grid-template-columns:repeat(6,1fr)}
    .grid--2:has(> :nth-child(5):last-child) > :nth-child(-n+3),
    .grid--3:has(> :nth-child(5):last-child) > :nth-child(-n+3),
    .tiers:has(> :nth-child(5):last-child) > :nth-child(-n+3),
    .stats:has(> :nth-child(5):last-child) > :nth-child(-n+3){grid-column:span 2}
    .grid--2:has(> :nth-child(5):last-child) > :nth-child(n+4),
    .grid--3:has(> :nth-child(5):last-child) > :nth-child(n+4),
    .tiers:has(> :nth-child(5):last-child) > :nth-child(n+4),
    .stats:has(> :nth-child(5):last-child) > :nth-child(n+4){grid-column:span 3}
  }

  /* ── the narrow shell is 820px wide: two columns is its ceiling ──────── */
  /* The counted rules above are right for a full-width shell and wrong inside
     .shell--narrow. Four cards in an 820px shell became four ~150px columns --
     which is what the owner meant by "super smushed on the computer", and it
     had been true of /contact since long before the contact pages were added.

     The rules key on VIEWPORT width; the real constraint is the CONTAINER.
     Until container queries are worth the risk here, the narrow shell states
     its own ceiling, and specificity settles it: .shell--narrow .grid--2:has()
     is one class more specific than .grid--2:has(), so it wins without
     !important and without touching the wide-shell behaviour. */
  @media (min-width:1001px){
    .shell--narrow .grid--2:has(> :nth-child(3)),
    .shell--narrow .grid--3:has(> :nth-child(3)),
    .shell--narrow .tiers:has(> :nth-child(3)){grid-template-columns:repeat(2,1fr)}

    /* The five-card layout above spans cards across six tracks. With only two
       tracks those spans would overflow the row, so they are reset first. */
    .shell--narrow .grid--2:has(> :nth-child(3)) > :nth-child(n),
    .shell--narrow .grid--3:has(> :nth-child(3)) > :nth-child(n),
    .shell--narrow .tiers:has(> :nth-child(3)) > :nth-child(n){grid-column:auto}

    /* An odd count strands the last card beside a gap, so it takes the row --
       the same answer the 641-1000px band already gives. */
    .shell--narrow .grid--2:has(> :nth-child(odd):last-child) > :nth-child(odd):last-child,
    .shell--narrow .grid--3:has(> :nth-child(odd):last-child) > :nth-child(odd):last-child,
    .shell--narrow .tiers:has(> :nth-child(odd):last-child) > :nth-child(odd):last-child{grid-column:1 / -1}
  }

  /* ── middle: 641 to 1000px ───────────────────────────────────────────── */
  @media (min-width:641px) and (max-width:1000px){
    .grid--2:has(> :nth-child(2):last-child),
    .grid--3:has(> :nth-child(2):last-child),
    .tiers:has(> :nth-child(2):last-child),
    .grid--2:has(> :nth-child(4):last-child),
    .grid--3:has(> :nth-child(4):last-child),
    .tiers:has(> :nth-child(4):last-child),
    .stats:has(> :nth-child(4):last-child),
    .grid--2:has(> :nth-child(6):last-child),
    .grid--3:has(> :nth-child(6):last-child),
    .tiers:has(> :nth-child(6):last-child),
    .grid--2:has(> :nth-child(5):last-child),
    .grid--3:has(> :nth-child(5):last-child),
    .tiers:has(> :nth-child(5):last-child),
    .stats:has(> :nth-child(5):last-child){grid-template-columns:repeat(2,1fr)}

    /* five at two columns is 2 + 2 + 1, so the fifth takes the whole last row
       rather than half of it. The row is still full. */
    .grid--2:has(> :nth-child(5):last-child) > :nth-child(5),
    .grid--3:has(> :nth-child(5):last-child) > :nth-child(5),
    .tiers:has(> :nth-child(5):last-child) > :nth-child(5),
    .stats:has(> :nth-child(5):last-child) > :nth-child(5){grid-column:1 / -1}

    /* three stacks rather than sitting 2 + 1 */
    .grid--2:has(> :nth-child(3):last-child),
    .grid--3:has(> :nth-child(3):last-child),
    .tiers:has(> :nth-child(3):last-child),
    .mm-quotes:has(> :nth-child(3):last-child){grid-template-columns:1fr}
  }

  /* ── narrow: 640px and down ──────────────────────────────────────────── */
  /* Counted selectors here too, not `:has(> *)`. That shorthand was tried and
     silently matched nothing in this band, leaving .stats on its auto-fit
     default at 620-640px -- three columns and a stranded fourth figure.
     Whatever the reason, the count-based form is the one proven to work in
     the two bands above, so the block uses one shape throughout. */
  @media (max-width:640px){
    .grid--2:has(> :nth-child(2)),
    .grid--3:has(> :nth-child(2)),
    .tiers:has(> :nth-child(2)),
    .mm-quotes:has(> :nth-child(2)){grid-template-columns:1fr}
    .grid--2:has(> :nth-child(2)) > :nth-child(n),
    .grid--3:has(> :nth-child(2)) > :nth-child(n),
    .tiers:has(> :nth-child(2)) > :nth-child(n){grid-column:auto}

    /* the figures stay two across -- one per row makes a short number look
       like a headline and pushes everything under it off the screen */
    .stats:has(> :nth-child(2)){grid-template-columns:1fr 1fr}
    .stats:has(> :nth-child(2)) > :nth-child(n){grid-column:auto}
    /* an odd count still strands the last figure, so it takes the row */
    .stats:has(> :nth-child(odd):last-child) > :nth-child(odd):last-child{grid-column:1 / -1}
  }
}

/* ── pricing cards ─────────────────────────────────────────────────────── */
.tiers{display:grid;gap:clamp(16px,2.4vw,22px);
       grid-template-columns:repeat(auto-fit,minmax(min(100%,258px),1fr));
       align-items:stretch}
.tier{background:var(--white);border:1px solid var(--rule);border-radius:3px;
      padding:clamp(22px,2.8vw,30px);display:flex;flex-direction:column;
      position:relative;transition:border-color .3s var(--ease),box-shadow .3s var(--ease)}
.tier:hover{border-color:var(--clay)}
.tier--featured{border-color:var(--clay);box-shadow:0 20px 46px -30px rgba(61,51,48,.42)}
.tier__flag{position:absolute;top:-1px;right:18px;transform:translateY(-50%);
            background:var(--clay);color:var(--white);font-size:10px;font-weight:600;
            letter-spacing:.15em;text-transform:uppercase;padding:5px 11px;border-radius:2px}
.tier__name{font-family:var(--display);font-size:24px;color:var(--ink);margin-bottom:5px}
.tier__line{font-size:var(--t-small);color:var(--muted);margin-bottom:20px;min-height:2.6em}
.tier__price{display:flex;align-items:baseline;gap:7px;margin-bottom:3px}
.tier__price b{font-family:var(--display);font-size:38px;font-weight:500;color:var(--ink);
               font-variant-numeric:tabular-nums;line-height:1}
.tier__price span{font-size:13.5px;color:var(--muted)}
.tier__alt{font-size:var(--t-fine);color:var(--muted);margin-bottom:22px;min-height:1.5em}
.tier ul{list-style:none;margin-bottom:24px;flex:1}
/* Same construction, same reason. See the note above .ledger--plain li. */
.tier li{display:block;position:relative;padding-left:16px;
         padding-block:7px;font-size:var(--t-small);color:var(--body)}
.tier li::before{content:'';position:absolute;left:1px;top:calc(7px + .67em);
  width:5px;height:5px;border-radius:50%;background:var(--terracotta)}
.tier li.is-head{font-weight:600;color:var(--ink);padding-left:0;padding-top:14px}
.tier li.is-head::before{display:none}
.tier .fine{margin-top:11px;text-align:center}

/* ── the billing toggle ────────────────────────────────────────────────── */
.toggle{display:inline-flex;align-items:center;gap:3px;background:var(--sand);
        border-radius:999px;padding:4px;position:relative}
.toggle button{position:relative;z-index:2;font:inherit;font-size:13.5px;font-weight:600;
               padding:9px 20px;border:0;background:transparent;color:var(--muted);
               cursor:pointer;border-radius:999px;white-space:nowrap;
               transition:color .28s var(--ease)}
/* White only once JS has measured and placed the pill. Before that, and for
   good if the script never runs, the selected label stays --muted on --sand
   (5.16) instead of white on --sand (1.23, invisible). The pill is hidden in
   the same state so there is no stray clay lozenge parked at the left edge. */
.toggle.is-ready button[aria-pressed="true"]{color:var(--white)}
/* 44px on a touch screen. At 13.5px with 9px padding these measure 40, which
   is under the target minimum — caught on the plan pages, but /pricing has
   carried the same toggle and the same 4px shortfall all along. The pill is
   inset 4px top and bottom, so it grows with the buttons and stays aligned. */
@media (pointer:coarse){
  .toggle button{min-height:44px}
}
.toggle .pill{display:none;position:absolute;z-index:1;top:4px;bottom:4px;left:4px;
              background:var(--clay);border-radius:999px;
              transition:transform .34s var(--spring),width .34s var(--spring)}
.toggle.is-ready .pill{display:block}
.toggle .save{font-size:var(--t-fine);color:var(--clay-dark);margin-left:12px;white-space:nowrap}

/* ── comparison table ──────────────────────────────────────────────────── */
/* min-width:0 and max-width:100% are both load-bearing. Without them the
   table's own min-width:660px pushes this box wider than its parent instead
   of scrolling inside it, and the whole PAGE gains a horizontal scrollbar at
   375px. */
.compare-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;min-width:0;max-width:100%;
              border:1px solid var(--rule);border-radius:3px;background:var(--white)}
table.compare{border-collapse:collapse;width:100%;min-width:660px;font-size:var(--t-small)}
table.compare th,table.compare td{padding:13px 14px;text-align:center;
                                  border-bottom:1px solid var(--rule)}
/* Parked BELOW the site header, not at viewport top. .top is sticky at
   z-index 80, so a thead stuck at top:0 slides underneath it and the tier
   names read as ghosts through the blur. --top-h is the header's own height. */
table.compare thead th{position:sticky;top:var(--top-h,62px);background:var(--wash);z-index:2;
                       font-size:var(--t-label);font-weight:600;letter-spacing:.1em;
                       text-transform:uppercase;color:var(--muted)}
table.compare thead th b{display:block;font-family:var(--display);font-size:16px;
                         letter-spacing:0;text-transform:none;color:var(--ink);
                         font-weight:500;margin-bottom:2px}
table.compare th[scope="row"],table.compare td:first-child{text-align:left;
  position:sticky;left:0;background:var(--white);z-index:1;font-weight:400;color:var(--ink);
  min-width:236px}
table.compare thead th:first-child{background:var(--wash);z-index:3}
table.compare tr.group td{background:var(--wash);font-family:var(--display);font-size:15px;
                          color:var(--ink);padding-block:11px}
table.compare .yes{color:var(--clay);font-weight:600}
/* The "not included" marker is DRAWN, not typed. As a text character it needed
   4.5:1, and any colour that quiet failed while any colour that passed shouted
   as loudly as the clay check. As a graphical object it needs 3:1, so a short
   rule at #94866F (3.56 on white) is both compliant and correctly subdued.
   The cell carries a visually hidden "Not included" for screen readers, which
   is more reliable than aria-label on a <td>. */
table.compare .no{font-size:0;line-height:0}
table.compare .no::before{content:'';display:inline-block;width:11px;height:1.5px;
  background:#94866F;border-radius:1px;vertical-align:middle}
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
         overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
table.compare .part{font-size:var(--t-fine);color:var(--muted)}
table.compare tbody tr:hover td{background:var(--wash)}
table.compare tbody tr:hover td:first-child{background:var(--wash)}

/* ── FAQ ───────────────────────────────────────────────────────────────── */
.faq{border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{list-style:none;cursor:pointer;padding:20px 44px 20px 0;position:relative;
             font-family:var(--display);font-size:18px;color:var(--ink);line-height:1.3}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'';position:absolute;right:8px;top:50%;width:9px;height:9px;
  border-right:1.5px solid var(--clay);border-bottom:1.5px solid var(--clay);
  transform:translateY(-70%) rotate(45deg);transition:transform .3s var(--ease)}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq summary:hover{color:var(--clay-deep)}
.faq .answer{padding:0 0 22px;font-size:15.5px;color:var(--body)}
.faq .answer p + p{margin-top:13px}

/* ── the closing block ─────────────────────────────────────────────────── */
.close-block{background:var(--clay);color:var(--white);border-radius:3px;
             padding:clamp(30px,5vw,58px);text-align:center}
.close-block h2{color:var(--white);margin-bottom:14px}
.close-block p{color:rgba(255,255,255,.94);max-width:52ch;margin:0 auto 26px;
               font-size:16.5px}
/* Solid white. An 86% white composites over clay to #F3E7E4 and measures
   4.28, under AA for an 11px label. Solid is 5.17. The body copy below sits
   at 94% and measures 4.75, which clears. */
.close-block .eyebrow{color:var(--white);margin-bottom:14px}
.close-block .sig{font-family:var(--display);font-style:italic;font-size:16px;
                  color:rgba(255,255,255,.9);margin-top:24px}

/* ── footer ────────────────────────────────────────────────────────────── */
.foot{border-top:1px solid var(--rule);padding-block:clamp(40px,6vw,62px);
      font-size:var(--t-small)}
.foot .cols{display:grid;gap:var(--gap);
            grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
.foot h4{font-family:var(--sans);font-size:var(--t-label);font-weight:600;
         letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin-bottom:14px}
.foot ul{list-style:none}
.foot li{padding-block:5px}
.foot a{color:var(--body);text-decoration:none}
.foot a:hover{color:var(--clay-deep);text-decoration:underline}
.foot .base{margin-top:clamp(28px,4vw,44px);padding-top:22px;border-top:1px solid var(--rule);
            display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
            font-size:var(--t-fine);color:var(--muted)}


/* ── preview navigator ──────────────────────────────────────────────────
   The panel listing every page on the site now lives in
   js/mm-preview-nav.js, which is loaded on ALL ~97 pages rather than the
   fourteen this stylesheet reaches, and renders inside a shadow root so it
   is identical on the old pages and cannot trade styles with any of them.
   Nothing for this stylesheet to do. --------------------------------- */

/* ── motion ────────────────────────────────────────────────────────────── */
.reveal{opacity:0;transform:translateY(20px);
        transition:opacity .78s var(--ease),transform .78s var(--ease)}
.reveal.is-in{opacity:1;transform:none}
.reveal[data-d="1"]{transition-delay:.08s}
.reveal[data-d="2"]{transition-delay:.16s}
.reveal[data-d="3"]{transition-delay:.24s}
.reveal[data-d="4"]{transition-delay:.32s}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
                       transition-duration:.001ms!important;transition-delay:0s!important}
  /* Zeroing the durations is not enough on its own: anything that starts at
     opacity 0 and is animated to 1 would still need its animation to have
     RUN. These end states are therefore declared outright, so a reader with
     reduced motion gets a finished page rather than a fast one. */
  .reveal,.up,.rv-group > *,.mm-shot{opacity:1;transform:none}
  .lines .l > span{transform:none}
  .wash{display:none}
  .draw path,.draw line,.draw circle,.draw rect,.draw polyline{stroke-dashoffset:0}
  .top .prog{display:none}
}

/* ══════════════════════════════════════════════════════════════════════════
   MOTION

   The redesign's own pages disagreed with each other about how much a page
   should move. /la-soglia and /upgrade came from the artifacts and carry eight
   keyframes each -- an ambient wash, headlines rising out of a mask, a
   staggered cascade, marks that draw themselves. The pages generated for this
   branch -- /, /pricing, the plan pages, every /features page -- carry ZERO,
   and one transition between them. That gap is the whole of "we are missing
   the abundance and the effects and the investment in animation".

   So the vocabulary lives here, once, and every page on this stylesheet can
   use it. Six pieces:

     .wash      ambient blurred colour, drifting slowly behind a hero
     .lines     a headline whose lines rise out of a mask, on load
     .up        anything else in a hero, fading up on the same clock
     .rv-group  children cascade one after another when the group arrives
     .draw      an SVG mark that draws itself in
     .countup   a number that counts to its value

   Two rules govern all of it. Every piece is inert without its .is-in class,
   which la-soglia.js adds and which resolves towards SHOWN on any failure --
   a reveal that never fires is an invisible page. And the whole file is
   switched off wholesale by the reduced-motion block at the end, which was
   already there and now covers these too.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── ambient wash ──────────────────────────────────────────────────────── */
/* Three soft blurred discs that drift on different clocks, so the light
   behind a hero never sits still and never repeats. pointer-events:none
   because it must never be in the way of the text on top of it. */
.wash{position:absolute;inset:-18% -8% auto -8%;height:132%;pointer-events:none;
      z-index:0}
.wash i{position:absolute;display:block;border-radius:50%;filter:blur(58px);
        animation:mmDrift 24s ease-in-out infinite alternate}
.wash i:nth-child(1){width:46vw;height:34vw;left:2%;top:4%;
                     background:rgba(197,107,74,.15)}
.wash i:nth-child(2){width:38vw;height:30vw;right:4%;top:0;
                     background:rgba(226,214,196,.5);animation-delay:-8s}
.wash i:nth-child(3){width:30vw;height:24vw;left:34%;top:26%;
                     background:rgba(239,231,220,.55);animation-delay:-15s}
@keyframes mmDrift{
  from{transform:translate3d(0,0,0) scale(1)}
  to{transform:translate3d(2.4rem,-1.7rem,0) scale(1.09)}
}
/* Anything sharing a box with a wash has to be lifted above it -- and the
   CONTAINER has to do the clipping, not the wash. The wash is deliberately
   wider than its box (inset -8% each side) so the light runs off the edges
   rather than stopping in a visible line; with overflow only on the wash
   itself, that extra width widened the page instead. Measured: 26px of
   horizontal scroll at 320 and 115px at 1440, on every page with a hero.
   `clip` rather than `hidden` because hidden makes this a scroll container,
   which is the trap that broke the sticky header on /host-a-session. */
.has-wash{position:relative;isolation:isolate;overflow:clip}
.has-wash > *:not(.wash){position:relative;z-index:1}

/* ── the headline rises out of a mask ──────────────────────────────────── */
/* One .l per line. The mask is the page's own idea: a threshold you cross. */
.lines .l{display:block;overflow:hidden;padding-bottom:.09em}
.lines .l > span{display:block;transform:translateY(112%);
                 animation:mmRise 1.05s var(--ease) forwards;
                 animation-delay:var(--d,0s)}
@keyframes mmRise{to{transform:none}}

/* ── everything else in a hero, on the same clock ──────────────────────── */
.up{opacity:0;animation:mmUp .85s var(--ease) forwards;animation-delay:var(--d,0s)}
@keyframes mmUp{from{opacity:0;transform:translateY(15px)}to{opacity:1;transform:none}}

/* ── a group whose children arrive one after another ───────────────────── */
/* Deliberately CSS nth-child rather than a per-element delay attribute: the
   markup stays clean and reordering the children reorders the cascade. */
.rv-group > *{opacity:0;transform:translateY(16px)}
.rv-group.is-in > *{opacity:1;transform:none;
  transition:opacity .66s var(--ease),transform .66s var(--ease)}
.rv-group.is-in > *:nth-child(1){transition-delay:0s}
.rv-group.is-in > *:nth-child(2){transition-delay:.07s}
.rv-group.is-in > *:nth-child(3){transition-delay:.14s}
.rv-group.is-in > *:nth-child(4){transition-delay:.21s}
.rv-group.is-in > *:nth-child(5){transition-delay:.28s}
.rv-group.is-in > *:nth-child(6){transition-delay:.35s}
.rv-group.is-in > *:nth-child(7){transition-delay:.42s}
.rv-group.is-in > *:nth-child(8){transition-delay:.49s}
.rv-group.is-in > *:nth-child(n+9){transition-delay:.56s}

/* ── marks that draw themselves ────────────────────────────────────────── */
/* --len is the path length, set per shape. A wrong --len still ends at
   dashoffset 0, so the mark is always complete once the animation finishes. */
.draw path,.draw line,.draw circle,.draw rect,.draw polyline{
  stroke-dasharray:var(--len,140);stroke-dashoffset:var(--len,140)}
.draw.is-in path,.draw.is-in line,.draw.is-in circle,.draw.is-in rect,
.draw.is-in polyline{animation:mmDraw 1.05s var(--ease) forwards;
                     animation-delay:var(--d,0s)}
@keyframes mmDraw{to{stroke-dashoffset:0}}

/* ── a figure arriving ─────────────────────────────────────────────────── */
/* The renderings are the one place on these pages with real visual weight,
   so they get their own arrival rather than the generic fade: a slight scale
   settling out, which reads as a photograph being set down. */
.mm-shot{opacity:0;transform:translateY(18px) scale(.985);
         transition:opacity .8s var(--ease),transform .8s var(--ease)}
.mm-shot.is-in{opacity:1;transform:none}

/* ── the hero ──────────────────────────────────────────────────────────── */
/* Two columns from 960px, where there is room for a 1024px-wide rendering to
   sit beside a 62ch measure without either being squeezed. Below that they
   stack in reading order, which is what the source order already is -- no
   grid-row reordering, so what a screen reader hears is what a sighted reader
   sees, at every width. */
.hero{display:grid;gap:clamp(26px,3.4vw,44px);align-items:center}
.hero-see{margin:0}
/* The two calls to action. In a 570px hero column they cannot sit side by
   side without the second one wrapping its own label, so they stack -- and if
   they are going to stack they must be the same width, or the pair reads as
   two unrelated buttons rather than a primary and its alternative.
   max-width:none cancels the global p{max-width:66ch}, which was clamping the
   row itself and is why they wrapped raggedly to begin with. */
.btn-row{display:flex;gap:12px;flex-wrap:wrap;max-width:none}
@media(min-width:520px){
  .btn-row{flex-direction:column;align-items:stretch;max-width:400px}
}
.hero .stats{grid-column:1 / -1}
@media(min-width:960px){
  .hero{grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr)}
  .hero-say{min-width:0}
}

/* ── a row of figures ──────────────────────────────────────────────────── */
/* Ruled, not carded: four cells divided by hairlines, the figure large in the
   display face and its label small above it. Numbers read down-then-across on
   a phone, where four columns would leave each figure in a 70px box. */
.stats{display:grid;gap:0;margin-top:clamp(30px,4.5vw,46px);
       grid-template-columns:repeat(auto-fit,minmax(min(100%,170px),1fr));
       border-top:1px solid var(--rule)}
.stats > div{padding:16px 18px 18px;border-bottom:1px solid var(--rule);
             border-right:1px solid var(--rule)}
.stats > div:last-child{border-right:0}
.stats dt{font-size:var(--t-fine);line-height:1.45;color:var(--muted);
          max-width:22ch;order:2;margin-top:4px}
.stats dd{font-family:var(--display);font-size:clamp(30px,4vw,40px);line-height:1;
          color:var(--ink);letter-spacing:-.02em;order:1}
.stats > div{display:flex;flex-direction:column}
@media(max-width:600px){
  .stats{grid-template-columns:1fr 1fr}
  /* On two columns the right-hand border of every second cell is the page
     edge, so it has to come off or it reads as a stray line. */
  .stats > div:nth-child(2n){border-right:0}
  .stats > div{padding:13px 14px 15px}
}

/* ── reading progress ──────────────────────────────────────────────────── */
/* A hairline across the bottom of the sticky header. Width is set by script
   as a transform, never as a width, so it never triggers layout. */
.top .prog{position:absolute;left:0;right:0;bottom:-1px;height:2px;
  transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,var(--terracotta),var(--clay));
  will-change:transform}

/* ── a number counting to its value ────────────────────────────────────── */
.countup{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ══════════════════════════════════════════════════════════════════════════
   WRITTEN FOR A PHONE

   Everything above this point sizes itself with clamp(), and until this block
   existed there was no typographic rule below 900px at all -- only the nav and
   two grids had breakpoints. clamp() gets the SIZES roughly right and gets the
   RHYTHM wrong, because rhythm is a ratio between measure and leading, and the
   measure collapses on a phone while the leading does not:

     1440px   16px / 1.7   in a 66-character measure   -> reads as paragraphs
      390px   16px / 1.7   in a 44-character measure   -> reads as a stack of
                                                          separate lines

   So this block is not "make it smaller". It is the leading, the gaps between
   blocks and the touch targets, set for the width they are actually used at.
   ══════════════════════════════════════════════════════════════════════════ */

/* Adjacent paragraphs had NO gap at all. The reset zeroes every margin and
   each page then hand-set `style="margin-top:22px"` per paragraph -- so
   wherever someone forgot, two paragraphs ran together with nothing between
   them. There are three such places in the current pages. A default here
   fixes them and cannot double up, because an inline margin-top still wins. */
p + p, p + ul, p + ol, ul + p, ol + p { margin-top: 1.05em }

@media (max-width: 600px) {
  body { line-height: 1.6 }
  .lead { line-height: 1.5 }
  h1 { line-height: 1.1 }
  h2 { line-height: 1.14 }
  h3 { line-height: 1.3 }
  p + p, p + ul, p + ol, ul + p, ol + p { margin-top: 1em }

  /* Two 56px section paddings meet as 112px of nothing between a sand band
     and a white one, which on a 844px screen is an eighth of the phone spent
     on a gap. Tightened, not removed -- the air is the brand. */
  :root { --section: 52px; --gap: 22px }
  .section--tight { padding-block: 34px }

  /* The list was 15px type on a 25.5px line with 13px of padding on each row:
     four items filled the screen and the rhythm read as loose rather than
     considered. */
  .ledger li { padding-block: 11px; font-size: 15px }
  .ledger--plain li { padding-left: 19px }
  .ledger--plain li::before { top: calc(11px + .66em) }

  /* Two side-by-side buttons do not fit at 390px; they wrapped into a ragged
     stack of different widths. Full width, stacked, is what a phone wants,
     and it makes both a proper touch target. */
  .btn--lg { width: 100%; padding: 16px 22px }
  .btn--lg + .btn--lg { margin-top: 10px }

  .card, .tier { padding: 22px 20px }
  .panel { padding: 22px 20px }

  /* Anything anchored to sits under a 84px sticky header on this breakpoint
     (--top-h), so without this every in-page jump lands with its heading
     hidden behind the bar. */
  [id] { scroll-margin-top: calc(var(--top-h) + 12px) }
}

/* Small phones -- 360px and the 320px iPhone SE still in the analytics. */
@media (max-width: 380px) {
  :root { --section: 44px }
  .shell { padding-inline: 17px }
  .ledger li { font-size: 14.5px }
}

/* ── a sequence, numbered ───────────────────────────────────────────────────
   Seven feature pages each describe the same shape: four steps in order. A
   plain <ol> loses the order the moment it wraps to one column on a phone, so
   the numeral is drawn rather than left to the list marker, and it stays on the
   rule beside the step at every width. */
.walk{list-style:none;counter-reset:walk;margin-top:clamp(22px,3vw,32px)}
.walk li{counter-increment:walk;position:relative;padding:22px 0 22px 58px;
  border-top:1px solid var(--rule)}
.walk li:last-child{border-bottom:1px solid var(--rule)}
.walk li::before{content:counter(walk,decimal-leading-zero);position:absolute;
  left:0;top:21px;font-family:var(--display);font-size:19px;line-height:1;
  color:var(--clay);font-variant-numeric:tabular-nums}
.walk strong{display:block;font-family:var(--display);font-size:clamp(17px,2vw,19px);
  font-weight:500;color:var(--ink);line-height:1.3;margin-bottom:7px}
.walk span{display:block;font-size:15px;line-height:1.65;color:var(--body)}
@media (max-width:600px){
  .walk li{padding:18px 0 18px 44px}
  .walk li::before{top:18px;font-size:17px}
  .walk span{font-size:14.5px}
}

/* ── the two legal pages ────────────────────────────────────────────────────
   /privacy and /terms are the last two pages a visitor can reach from the
   footer of every other page, so they had to stop saying "RISING & THRIVING".
   The policy text itself is carried over word for word; this is only the
   typography it lands in. Numbered sections, a metadata block at the top, one
   table each, and a notice callout. Nothing here is decorative -- a legal page
   that is hard to read is a legal page nobody reads. */
.legal{max-width:74ch;font-size:15.5px;line-height:1.72;color:var(--body)}
.legal h2{font-size:clamp(19px,2.4vw,23px);margin:clamp(38px,5vw,52px) 0 14px;
  padding-top:clamp(24px,3vw,32px);border-top:1px solid var(--rule)}
.legal h2:first-child{margin-top:0;padding-top:0;border-top:0}
.legal h3{font-size:clamp(16px,2vw,18px);margin:30px 0 10px}
.legal h4{font-family:var(--sans);font-size:13px;font-weight:600;letter-spacing:.03em;
  text-transform:uppercase;color:var(--muted);margin:24px 0 8px}
.legal p{margin:0 0 14px}
.legal ul{list-style:none;margin:0 0 18px;padding:0}
.legal ul li{position:relative;padding:0 0 0 19px;margin-bottom:9px}
.legal ul li::before{content:'';position:absolute;left:1px;top:calc(.68em);
  width:5px;height:5px;border-radius:50%;background:var(--terracotta)}
.legal a{color:var(--clay-deep)}
.legal .metadata{background:var(--sand);border-radius:3px;
  padding:clamp(20px,3vw,26px);margin-bottom:clamp(26px,3.5vw,34px)}
.legal .metadata p{margin:0 0 7px;font-size:14.5px}
.legal .metadata p:last-child{margin-bottom:0}
/* The old page painted its critical notice red on red. On this ground the
   clay rule carries the same weight without the alarm -- and it stays legible,
   which red-on-red at 14px was not. */
.legal .notice{border-left:3px solid var(--clay);padding:2px 0 2px 20px;
  margin:0 0 clamp(30px,4vw,40px)}
.legal .notice p{margin:0}
.legal .notice strong{color:var(--clay-dark)}
/* the one wide table on each page keeps its own scroller at every width */
.legal .scroller{overflow-x:auto;margin-bottom:22px;-webkit-overflow-scrolling:touch}
.legal .scroller table{margin-bottom:0}
.legal table{width:100%;border-collapse:collapse;margin:6px 0 22px;font-size:14.5px}
.legal th,.legal td{text-align:left;padding:11px 14px 11px 0;
  border-bottom:1px solid var(--rule);vertical-align:top}
.legal th{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);border-bottom-color:var(--ink)}
@supports (top: 1lh){ .legal ul li::before{top:calc((1lh - 5px) / 2)} }
@media (max-width:600px){
  .legal{font-size:15px}
  /* a four-column table cannot fit 320px; the .scroller wrapper handles the
     overflow, so here it only needs to stop wrapping into unreadable columns */
  .legal table{min-width:520px}
}

/* ── a form ─────────────────────────────────────────────────────────────────
   The webinar registration page is the first page in this design system with
   an input on it, so this is the whole of the form vocabulary rather than a
   one-page override.

   The 16px font size on inputs is load-bearing and not a typo: iOS Safari
   zooms the viewport on focus for anything smaller, and the page never zooms
   back out. A registration form that leaves the visitor stranded at 1.3x is
   worse than one that looks slightly large on desktop. */
.lbl{display:block;font-family:var(--sans);font-size:var(--t-fine);font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin:14px 0 6px}
.lbl:first-child{margin-top:0}
.panel input[type=text],.panel input[type=email],
input.mm-field{
  display:block;width:100%;box-sizing:border-box;
  font-family:var(--sans);font-size:16px;line-height:1.4;color:var(--ink);
  background:var(--white);border:1px solid var(--rule);border-radius:3px;
  padding:12px 14px;transition:border-color .18s ease,box-shadow .18s ease}
.panel input::placeholder{color:var(--muted);opacity:.75}
.panel input:focus-visible{outline:none;border-color:var(--clay);
  box-shadow:0 0 0 3px rgba(168,86,59,.15)}
.panel input[aria-invalid="true"]{border-color:var(--clay-dark)}
.panel button[disabled]{opacity:.55;cursor:default}
.fineprint{margin-top:12px;font-size:13.5px;line-height:1.55;color:var(--muted);
  min-height:1.2em}

/* ══════════════════════════════════════════════════════════════════════════
   LIVE RENDERINGS OF THE SYSTEM

   These replace the screenshots. A screenshot of the product is a 1MB PNG that
   is fixed at one size, cannot be read by a search engine, goes stale the day
   the product changes, and cannot animate. These are the same screens drawn in
   HTML: a few kilobytes, sharp at any width, and able to arrive.

   The palettes are NOT invented. They are the real tokens out of the live
   sheet files on origin/main:

     DashboardHTML.html        --income #567b84   --expense #ab9478
                               --neutral #e4e0d8  --neutral-light #f5f3ef
                               --black #394144
     CategorizationModal.html  --color-primary #ab9478   --color-dark #8a7760
                               --color-income #51cf66    --color-expense #ff6b6b
                               --color-need #c9a227      --color-desire #3E5C65
                               --row-height 52px

   So what a visitor sees here is the colour the screen actually is.

   Every rendering is a DEPICTION, not a screenshot, and every figure in one is
   an example. They are labelled as such in their captions.
   ══════════════════════════════════════════════════════════════════════════ */

.mmr{
  --r-ink:#394144; --r-mute:#7A7168; --r-line:#E4E0D8; --r-ground:#F5F3EF;
  --r-teal:#567b84; --r-teal-dk:#4a6b73; --r-taupe:#ab9478; --r-taupe-dk:#8a7760;
  --r-green:#1a7a4c; --r-red:#b91c1c; --r-need:#c9a227; --r-desire:#3E5C65;
  --r-gold:#c9aa7a;
  background:#fff;border:1px solid var(--rule);border-radius:3px;overflow:hidden;
  font-family:var(--sans);color:var(--r-ink);container-type:inline-size;margin:0;
}
.mmr *{box-sizing:border-box}
/* A dashboard is a full screen and should fill the column. A modal and a
   helper panel are not: the real split modal is about 600px and the real
   Clarity panel is a sidebar, so stretched to 1084px they stop reading as
   the thing they are drawing, and the brief's lines run past 150 characters.
   Panels get a believable width and sit centred. */
.mmr--panel{max-width:660px;margin-inline:auto}
.mmr-bar{display:flex;align-items:center;gap:9px;padding:9px 13px;
  background:var(--r-taupe);color:#fff;font-size:12px;font-weight:600;letter-spacing:.02em}
.mmr-bar .dots{display:flex;gap:4px;margin-right:3px}
.mmr-bar .dots i{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.45)}
.mmr-bar .grow{margin-left:auto;font-weight:500;opacity:.85;font-size:11px}
.mmr-body{padding:13px;background:var(--r-ground)}
.mmr figcaption{
  padding:11px 14px 13px;border-top:1px solid var(--rule);background:var(--ground);
  font-size:13px;line-height:1.5;color:var(--muted)}

/* ── metric cards ───────────────────────────────────────────────────────── */
.mmr-kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin:0}
.mmr-kpi{background:#fff;border:1px solid var(--r-line);border-top:3px solid var(--r-line);
  border-radius:5px;padding:11px 12px 12px}
.mmr-kpi.is-in{border-top-color:var(--k,var(--r-teal))}
.mmr-kpi dt{font-size:9.5px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--r-mute)}
.mmr-kpi dd{margin:5px 0 0;font-size:clamp(15px,3.2cqi,21px);font-weight:700;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;color:var(--k,var(--r-teal))}
.mmr-kpi small{display:block;margin-top:3px;font-size:10.5px;color:var(--r-mute)}
@container (max-width:430px){.mmr-kpis{grid-template-columns:1fr}}

/* ── the twelve-month bar chart ─────────────────────────────────────────── */
.mmr-chart{margin-top:11px;background:#fff;border:1px solid var(--r-line);border-radius:5px;
  padding:12px 12px 8px}
.mmr-chart h4{font-size:11px;font-weight:700;letter-spacing:.06em;color:var(--r-ink);
  display:flex;align-items:center;gap:8px;margin-bottom:10px}
.mmr-legend{margin-left:auto;display:flex;gap:11px;font-size:10px;font-weight:500;color:var(--r-mute)}
.mmr-legend b{display:inline-flex;align-items:center;gap:4px;font-weight:500}
.mmr-legend i{width:8px;height:8px;border-radius:2px;display:inline-block}
.mmr-plot{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(3px,1cqi,7px);
  align-items:end;height:104px;border-bottom:1px solid var(--r-line);padding-bottom:1px}
.mmr-mo{display:flex;gap:2px;align-items:flex-end;height:100%}
.mmr-mo span{flex:1;border-radius:2px 2px 0 0;height:0;
  transition:height .9s cubic-bezier(.22,.61,.36,1) var(--bd,0s)}
.mmr-mo .i{background:var(--r-teal)}
.mmr-mo .e{background:var(--r-taupe)}
/* Two reveal classes, because two pages drive this differently: la-soglia.js
   adds .is-in, and /upgrade -- which is the artifact port and does not load
   la-soglia.js -- has its own observer that adds .in to [data-rv]. A
   rendering that never receives either is an invisible block of content, so
   it answers to both rather than assuming one. */
.mmr.is-in .mmr-mo span,.mmr.in .mmr-mo span{height:var(--h)}
.mmr-months{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(3px,1cqi,7px);
  margin-top:5px;font-size:8.5px;color:var(--r-mute);text-align:center;letter-spacing:.02em}
@container (max-width:430px){.mmr-months{font-size:7px}}

/* ── top income / top expenses ──────────────────────────────────────────── */
.mmr-tops{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:11px}
.mmr-top{background:#fff;border:1px solid var(--r-line);border-radius:5px;padding:10px 11px}
.mmr-top h4{font-size:9.5px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--r-mute);margin-bottom:7px}
.mmr-top ul{list-style:none;margin:0;padding:0}
.mmr-top li{display:flex;justify-content:space-between;gap:10px;padding:5px 0;
  font-size:11.5px;border-bottom:1px solid #F1EEE8}
.mmr-top li:last-child{border-bottom:0}
.mmr-top b{font-weight:600;font-variant-numeric:tabular-nums}
@container (max-width:430px){.mmr-tops{grid-template-columns:1fr}}

/* ── the categorization room ────────────────────────────────────────────── */
.mmr-tools{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:9px 11px;
  background:var(--r-taupe-dk);color:#fff}
.mmr-chip{font-size:10px;font-weight:600;letter-spacing:.04em;padding:4px 9px;border-radius:99px;
  background:rgba(255,255,255,.16);white-space:nowrap}
.mmr-chip.on{background:#fff;color:var(--r-taupe-dk)}
.mmr-search{flex:1;min-width:90px;font-size:10.5px;padding:5px 9px;border-radius:4px;
  background:rgba(255,255,255,.15);color:rgba(255,255,255,.85)}
.mmr-apply{font-size:10px;font-weight:700;letter-spacing:.04em;padding:5px 11px;border-radius:4px;
  background:var(--r-gold);color:#3B3126;white-space:nowrap}
.mmr-rows{background:#fff}
.mmr-row{display:grid;align-items:center;gap:8px;padding:8px 11px;
  grid-template-columns:14px 52px minmax(0,1fr) 74px 96px 60px 46px;
  border-bottom:1px solid #F1EEE8;font-size:11.5px;
  opacity:0;transform:translateY(6px);
  transition:opacity .5s var(--ease) var(--rd,0s),transform .5s var(--ease) var(--rd,0s)}
.mmr.is-in .mmr-row,.mmr.in .mmr-row{opacity:1;transform:none}
.mmr-row:last-child{border-bottom:0}
.mmr-box{width:13px;height:13px;border:1.5px solid var(--r-line);border-radius:3px}
.mmr-row.pick .mmr-box{background:var(--r-taupe);border-color:var(--r-taupe)}
.mmr-date{color:var(--r-mute);font-size:10.5px;font-variant-numeric:tabular-nums}
.mmr-desc{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:500}
.mmr-amt{text-align:right;font-weight:700;font-variant-numeric:tabular-nums}
.mmr-amt.in{color:var(--r-green)}
.mmr-amt.out{color:var(--r-red)}
.mmr-sel{border:1px solid var(--r-line);border-radius:4px;padding:4px 7px;font-size:10.5px;
  background:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mmr-sel.suggested{background:#f8f0e3;border-color:var(--r-gold)}
.mmr-tag{font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:3px 7px;border-radius:99px;color:#fff;text-align:center}
.mmr-tag.need{background:var(--r-need);color:#3B3126}
.mmr-tag.desire{background:var(--r-desire)}
.mmr-mini{display:flex;gap:4px;justify-content:flex-end;color:var(--r-mute);font-size:10px}
.mmr-mini span{border:1px solid var(--r-line);border-radius:3px;padding:2px 5px;line-height:1}
@container (max-width:520px){
  .mmr-row{grid-template-columns:14px minmax(0,1fr) 70px;row-gap:5px}
  .mmr-date,.mmr-mini{display:none}
  .mmr-sel{grid-column:2/-1}
  .mmr-tag{grid-column:2/3;justify-self:start;padding:3px 9px}
}

/* ── a finished report ──────────────────────────────────────────────────── */
.mmr-rep{background:#fff;padding:15px 15px 6px}
.mmr-rep h4{font-family:var(--display);font-size:clamp(14px,3.4cqi,19px);font-weight:600;
  text-align:center;color:var(--r-ink)}
.mmr-rep .when{text-align:center;font-size:10.5px;color:var(--r-mute);margin-top:2px;max-width:none}
.mmr-sum{list-style:none;margin:13px 0 0;padding:0}
.mmr-sum li{display:flex;justify-content:space-between;gap:12px;padding:6px 0;font-size:12px;
  border-bottom:1px solid #F1EEE8}
.mmr-sum li:last-child{border-bottom:0;border-top:1.5px solid var(--r-taupe);font-weight:700}
.mmr-sum b{font-variant-numeric:tabular-nums;font-weight:700}
.mmr-tbl{width:100%;border-collapse:collapse;margin-top:12px;font-size:10.5px;table-layout:fixed}
.mmr-tbl th{text-align:left;font-size:8.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--r-mute);padding:6px;border-bottom:1px solid var(--r-line);white-space:nowrap}
.mmr-tbl td{padding:6px;border-bottom:1px solid #F4F1EC;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mmr-tbl td:last-child,.mmr-tbl th:last-child{text-align:right;font-variant-numeric:tabular-nums}
.mmr-tbl tbody tr{opacity:0;transition:opacity .5s var(--ease) var(--rd,0s)}
.mmr.is-in .mmr-tbl tbody tr,.mmr.in .mmr-tbl tbody tr{opacity:1}

/* ── a ring, for the debt centre ────────────────────────────────────────── */
.mmr-ring{display:grid;place-items:center}
.mmr-ring svg{width:clamp(84px,22cqi,124px);height:auto;overflow:visible;display:block}
.mmr-ring circle{fill:none;stroke-width:11;stroke-linecap:butt}
.mmr-ring .track{stroke:#EFEAE1}
.mmr-ring .arc{stroke:var(--r-taupe);stroke-dasharray:var(--len);stroke-dashoffset:var(--len);
  transition:stroke-dashoffset 1.2s cubic-bezier(.22,.61,.36,1) .15s}
.mmr.is-in .mmr-ring .arc,.mmr.in .mmr-ring .arc{stroke-dashoffset:var(--off)}

/* ── progress rows, for savings, debt and net worth ─────────────────────── */
.mmr-prog{list-style:none;margin:0;padding:0}
.mmr-prog li{padding:7px 0;border-bottom:1px solid #F1EEE8;font-size:11.5px}
.mmr-prog li:last-child{border-bottom:0}
.mmr-prog .r{display:flex;justify-content:space-between;gap:10px;margin-bottom:5px}
.mmr-prog .r b{font-variant-numeric:tabular-nums;font-weight:600;color:var(--r-mute)}
.mmr-prog .t{height:6px;border-radius:99px;background:#EFEAE1;overflow:hidden;display:block}
.mmr-prog .t i{display:block;height:100%;width:0;border-radius:99px;background:var(--r-teal);
  transition:width 1.05s cubic-bezier(.22,.61,.36,1) var(--bd,0s)}
.mmr.is-in .mmr-prog .t i,.mmr.in .mmr-prog .t i{width:var(--w)}

/* ── the twelve tabs of the free tracker ────────────────────────────────── */
.mmr-tabs{display:flex;flex-wrap:wrap;gap:3px;padding:9px 11px;background:#fff;
  border-top:1px solid var(--r-line)}
.mmr-tabs span{font-size:9.5px;font-weight:600;letter-spacing:.02em;padding:3px 7px;
  border-radius:3px;background:var(--r-ground);color:var(--r-mute);white-space:nowrap}
.mmr-tabs span.on{background:var(--r-teal);color:#fff}

/* ── the split modal ────────────────────────────────────────────────────────
   Drawn from CategorizationModal.html on origin/main. The three states of the
   remaining box are that file's own, quoted here so the picture is honest:

     balanced   linear-gradient(135deg,#ebfbee,#d3f9d8)  border #51cf66
     under      linear-gradient(135deg,#fffbeb,#fff3cc)  border #f59f00
                "You still have $X left to allocate"     text  #e67700
     over       linear-gradient(135deg,#fff5f5,#ffe3e3)  border #ff6b6b
                "You've exceeded the total by $X"        text  #c92a2a

   The entry card is #f8f6f3 on an 80px 1fr 100px grid, the remove x is
   #ff6b6b, and Apply Split is the #3E5C65 -> #2d4a52 gradient and starts
   disabled -- all of that is the real file, not a guess.

   The animation tells the one story the page is about: two portions land, the
   box goes from amber to green, and only then does Apply light up. */
.mmr-split{padding:13px;background:var(--r-ground)}
.mmr-sp-head{background:var(--r-taupe);color:#fff;border-radius:5px 5px 0 0;
  padding:11px 13px;font-size:12px}
.mmr-sp-head b{display:block;font-weight:600;font-size:12.5px}
.mmr-sp-head small{display:block;margin-top:5px;font-size:12px;font-weight:700}
.mmr-sp-body{background:#fff;border:1px solid var(--r-line);border-top:0;
  border-radius:0 0 5px 5px;padding:11px}
.mmr-sp-e{background:#f8f6f3;border-radius:6px;padding:10px;margin-bottom:9px;
  opacity:0;transform:translateY(7px);
  transition:opacity .5s ease var(--sd,0s),transform .5s ease var(--sd,0s)}
.mmr.is-in .mmr-sp-e,.mmr.in .mmr-sp-e{opacity:1;transform:none}
.mmr-sp-e > b{display:flex;justify-content:space-between;align-items:center;
  font-size:11.5px;font-weight:600;margin-bottom:8px}
.mmr-sp-e > b i{font-style:normal;color:#ff6b6b;font-size:14px;line-height:1}
.mmr-sp-g{display:grid;grid-template-columns:74px minmax(0,1fr) 84px;gap:8px}
.mmr-sp-g label{display:block;font-size:10px;color:#666;margin-bottom:3px}
.mmr-sp-g u{display:block;text-decoration:none;border:1px solid #ddd;border-radius:5px;
  padding:6px 7px;font-size:11px;background:#fff;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.mmr-sp-g u.n{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
.mmr-sp-add{border:2px dashed var(--r-line);border-radius:6px;padding:8px;
  text-align:center;font-size:11px;font-weight:600;color:var(--r-taupe-dk)}
.mmr-sp-bal{margin-top:11px;padding:11px 13px;border-radius:7px;border:2px solid #f59f00;
  background:linear-gradient(135deg,#fffbeb 0%,#fff3cc 100%);
  transition:background .45s ease 1.05s,border-color .45s ease 1.05s}
.mmr-sp-bal .r{display:flex;justify-content:space-between;align-items:center;
  font-size:11.5px;font-weight:600}
.mmr-sp-bal .r em{font-style:normal;font-weight:800;font-size:16px;color:#e67700;
  font-variant-numeric:tabular-nums;transition:color .45s ease 1.05s}
.mmr-sp-bal .m{margin-top:5px;font-size:11px;font-weight:600;color:#e67700;
  transition:opacity .3s ease .95s}
.mmr.is-in .mmr-sp-bal,.mmr.in .mmr-sp-bal{border-color:#51cf66;
  background:linear-gradient(135deg,#ebfbee 0%,#d3f9d8 100%)}
.mmr.is-in .mmr-sp-bal .r em,.mmr.in .mmr-sp-bal .r em{color:#1a7a4c}
.mmr.is-in .mmr-sp-bal .m,.mmr.in .mmr-sp-bal .m{opacity:0}
.mmr-sp-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:11px}
.mmr-sp-foot span{font-size:11px;font-weight:700;padding:7px 14px;border-radius:5px;
  background:var(--r-ground);color:var(--r-mute)}
/* NOT .go -- that is the site's own "read more" affordance (uppercase,
   letter-spaced, clay) and it repainted this button's label. Renderings use
   short class names inside .mmr; any that is also a top-level site class has
   to be namespaced, and this was the one. */
.mmr-sp-foot span.mmr-go{background:linear-gradient(135deg,#3E5C65 0%,#2d4a52 100%);
  color:#fff;opacity:.4;transition:opacity .4s ease 1.3s}
.mmr.is-in .mmr-sp-foot span.mmr-go,.mmr.in .mmr-sp-foot span.mmr-go{opacity:1}
@container (max-width:380px){
  .mmr-sp-g{grid-template-columns:1fr 1fr;row-gap:7px}
  .mmr-sp-g > div:nth-child(2){grid-column:1/-1;order:3}
}

/* ── the account-upload panel ───────────────────────────────────────────────
   Also from CategorizationModal.html: an embedded panel on #f8f6f3, not a
   popup. Its two steps are the real ones -- pick a file and Preview, then
   "N transactions found - click any cell to edit, then add" over a
   110px 1fr 90px table, with the two repair buttons the file actually has
   ("Fix Dates (Swap Day/Month)", "Flip All Amounts"). Those two buttons are
   the point of the page, so they are drawn, not summarised. */
.mmr-up{background:#f8f6f3;padding:13px}
.mmr-up-step{display:flex;align-items:center;gap:9px;flex-wrap:wrap;font-size:11.5px}
.mmr-up-step strong{font-weight:600;font-size:11.5px}
.mmr-up-file{border:1px solid var(--r-line);border-radius:5px;background:#fff;
  padding:5px 9px;font-size:10.5px;color:var(--r-mute)}
.mmr-up-file b{font-weight:600;color:var(--r-ink)}
.mmr-btn{font-size:10.5px;font-weight:700;padding:5px 11px;border-radius:5px;
  background:#fff;border:1px solid var(--r-line);color:var(--r-taupe-dk)}
.mmr-btn.pri{background:var(--r-taupe);border-color:var(--r-taupe);color:#fff}
.mmr-up-fix{display:flex;gap:7px;flex-wrap:wrap;margin:10px 0 8px}
.mmr-up-hd{display:grid;grid-template-columns:78px minmax(0,1fr) 74px;gap:8px;
  padding:4px 9px;font-size:9px;font-weight:700;color:#888;letter-spacing:.06em;
  text-transform:uppercase}
.mmr-up-hd span:last-child{text-align:right}
.mmr-up-tbl{border:1px solid var(--r-line);border-radius:5px;background:#fff;
  overflow:hidden}
.mmr-up-tbl div{display:grid;grid-template-columns:78px minmax(0,1fr) 74px;gap:8px;
  padding:7px 9px;font-size:11px;border-bottom:1px solid var(--r-ground);
  opacity:0;transform:translateY(5px);
  transition:opacity .42s ease var(--ud,0s),transform .42s ease var(--ud,0s)}
.mmr.is-in .mmr-up-tbl div,.mmr.in .mmr-up-tbl div{opacity:1;transform:none}
.mmr-up-tbl div:last-child{border-bottom:0}
.mmr-up-tbl s{text-decoration:none;color:var(--r-mute);font-variant-numeric:tabular-nums}
.mmr-up-tbl q{quotes:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-weight:500}
.mmr-up-tbl b{text-align:right;font-weight:700;font-variant-numeric:tabular-nums}
.mmr-up-tbl b.in{color:var(--r-green)}
.mmr-up-tbl b.out{color:var(--r-red)}
@container (max-width:360px){
  .mmr-up-hd,.mmr-up-tbl div{grid-template-columns:minmax(0,1fr) 74px}
  .mmr-up-hd span:first-child,.mmr-up-tbl s{display:none}
}

/* ── Clarity ────────────────────────────────────────────────────────────────
   The helper panel out of the same file: an avatar, a greeting, and the three
   counters it actually keeps -- To Review, Issues, Learned -- over the ask
   box. The counters count up rather than appearing, because that is what they
   do on the screen as Clarity reads the sheet. */
.mmr-cl{padding:13px;background:var(--r-ground)}
.mmr-cl-top{display:flex;align-items:flex-start;gap:10px;background:#fff;
  border:1px solid var(--r-line);border-radius:6px;padding:11px}
.mmr-cl-av{flex:none;width:32px;height:32px;border-radius:50%;display:grid;
  place-items:center;font-size:15px;
  background:linear-gradient(135deg,#3E5C65 0%,#2d4a52 100%)}
.mmr-cl-top b{display:block;font-size:12px;font-weight:600}
.mmr-cl-top small{display:block;margin-top:3px;font-size:11px;color:var(--r-mute);
  line-height:1.45}
.mmr-cl-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:9px}
.mmr-cl-stat{background:#fff;border:1px solid var(--r-line);border-radius:6px;
  padding:9px 7px;text-align:center}
.mmr-cl-stat b{display:block;font-size:19px;font-weight:700;color:var(--r-desire);
  font-variant-numeric:tabular-nums;line-height:1.1}
.mmr-cl-stat small{display:block;margin-top:2px;font-size:9.5px;font-weight:600;
  letter-spacing:.07em;text-transform:uppercase;color:var(--r-mute)}
.mmr-cl-ask{display:flex;align-items:center;gap:7px;margin-top:9px;background:#fff;
  border:1px solid var(--r-line);border-radius:99px;padding:6px 6px 6px 13px;
  font-size:11px;color:var(--r-mute)}
.mmr-cl-ask i{margin-left:auto;flex:none;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;font-style:normal;font-size:12px;
  background:linear-gradient(135deg,#3E5C65 0%,#2d4a52 100%)}
.mmr-cl-brief{margin-top:9px;background:#fff;border:1px solid var(--r-line);
  border-radius:6px;padding:11px}
.mmr-cl-brief h5{margin:0 0 7px;font-size:9.5px;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--r-mute)}
.mmr-cl-brief li{list-style:none;display:flex;justify-content:space-between;gap:10px;
  padding:5px 0;font-size:11.5px;border-bottom:1px solid var(--r-ground);
  opacity:0;transform:translateY(5px);
  transition:opacity .42s ease var(--bd,0s),transform .42s ease var(--bd,0s)}
.mmr.is-in .mmr-cl-brief li,.mmr.in .mmr-cl-brief li{opacity:1;transform:none}
.mmr-cl-brief ul{margin:0;padding:0}
.mmr-cl-brief li:last-child{border-bottom:0}
.mmr-cl-brief li b{font-weight:700;color:var(--r-taupe-dk)}
.mmr-cl-brief li{display:block;line-height:1.5}
.mmr-cl-brief li .fine{display:block;font-size:10.5px;color:var(--r-mute);padding-top:2px}
.mmr-cl-brief .hd{margin:0 0 8px;font-family:var(--display);font-size:14px;
  font-weight:500;color:var(--r-ink);line-height:1.3}

@media (prefers-reduced-motion:reduce){
  .mmr-mo span{height:var(--h)!important;transition:none!important}
  .mmr-row,.mmr-tbl tbody tr{opacity:1!important;transform:none!important}
  .mmr-prog .t i{width:var(--w)!important}
  .mmr-ring .arc{stroke-dashoffset:var(--off)!important}
  .mmr-kpi{border-top-color:var(--k,var(--r-teal))!important}
  .mmr-sp-e,.mmr-up-tbl div,.mmr-cl-brief li{opacity:1!important;transform:none!important}
  .mmr-sp-bal{border-color:#51cf66!important;
    background:linear-gradient(135deg,#ebfbee 0%,#d3f9d8 100%)!important}
  .mmr-sp-bal .r em{color:#1a7a4c!important}
  .mmr-sp-bal .m{opacity:0!important}
  .mmr-sp-foot span.mmr-go{opacity:1!important}
}

/* ── the comparison table on a phone ─────────────────────────────────────────
   The owner, on an iPhone 17 Pro Max: "the side by side is broken".

   The desktop build leans on TWO-AXIS position:sticky inside a horizontal
   scroller: the row labels stick to the left while the tier names stick to the
   top. That is correct CSS and it is also one of the oldest unreliable corners
   of iOS Safari, where a sticky cell inside an overflow-x container can detach,
   double-paint, or float over the rows it is meant to label. On a desktop it is
   worth the risk because the whole table fits. On a phone it buys nothing,
   because a 660px table in a 440px window is being scrolled anyway.

   So below 760px the stickies come off and it becomes a plain scrolling table.
   Plain and reliable beats clever and broken, and I cannot test Safari from
   here, which is itself a reason to prefer the boring mechanism.

   The scroll also gets SAID, not just implied. A fade at the edge is a hint
   that a designer can read. The readers here are women in their forties to
   sixties who have no reason to guess that a table swipes, so there is a
   sentence above it instead.
   ──────────────────────────────────────────────────────────────────────────── */

.compare-hint { display: none; }

@media (max-width: 760px) {
  .compare-hint {
    display: block;
    margin: 0 0 10px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--muted);
  }
  .compare-hint b { color: var(--ink); font-weight: 600; }

  /* the whole sticky apparatus, off */
  table.compare thead th,
  table.compare th[scope="row"],
  table.compare td:first-child,
  table.compare thead th:first-child { position: static; }

  /* A narrower label column leaves room for two tier columns at a time rather
     than one and a sliver. */
  table.compare th[scope="row"],
  table.compare td:first-child { min-width: 168px; }
  table.compare { min-width: 560px; font-size: 15px; }
  table.compare th, table.compare td { padding: 12px 11px; }
  table.compare thead th b { font-size: 15px; }

  /* The scroller gets a visible edge so it reads as a panel you move, and a
     real scrollbar rather than the overlay one iOS hides after a second. */
  .compare-wrap {
    border-color: var(--clay);
    scrollbar-width: thin;
  }
  .compare-wrap::-webkit-scrollbar { height: 9px; }
  .compare-wrap::-webkit-scrollbar-thumb {
    background: var(--rule); border-radius: 9px;
  }
}

/* The "included" marker, DRAWN rather than typed, to match the "not included"
   rule above it. It was a ✓ character (&#10003;), which iOS renders with emoji
   styling in some contexts, and the owner's rule is "we never use emojis only
   icons". Forty of them in one table, so CSS draws it once instead of forty
   inline SVGs. Each cell still carries a visually hidden "Included" for screen
   readers, which is what actually conveys the meaning. */
table.compare .yes:not(.has-text) { font-size: 0; line-height: 0; }
table.compare .yes:not(.has-text)::before {
  content: '';
  display: inline-block;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--clay);
  border-bottom: 2px solid var(--clay);
  transform: rotate(-45deg) translateY(-2px);
  vertical-align: middle;
}
