/* ---------------------------------------------------------------------------
   BrassWell marketing site draft — shared stylesheet.
   Palette, fonts, and the ruled-ledger-paper motif are lifted directly from
   the live waitlist page (Brasswell Waitlist Site/worker.js) so this draft
   stays visually the same brand, not a new one. Structure (nav, hero, feature
   cards, alternating sections, FAQ, CTA banner) is modeled on lettuce.co.
--------------------------------------------------------------------------- */

:root{
  --pine:#1E3D2F; --pine-dk:#142B21; --pine-soft:#e3eee8;
  --rust:#B54B2A; --rust-soft:#f5e6e4;
  --brass:#b8862b; --brass-soft:#f5ebd6;
  --cream:#F4EFE1; --paper-card:#fcfdfb;
  --ink:#24211B; --grey:#6B675C;
  --line: rgba(30,61,47,0.14);
  --radius: 10px;

  /* ---- elevation ---------------------------------------------------------
     Three steps, all tinted pine rather than neutral black — a gray shadow on
     a cream page reads as dirt, a tinted one reads as depth. Each is two
     layers: a tight contact shadow that grounds the edge, and a wide diffuse
     one that lifts the whole card. Borrowed from the reference shot, where
     every surface is a card floating over the background rather than a panel
     drawn onto it. */
  --lift-1: 0 1px 2px rgba(30,61,47,.06), 0 4px 12px rgba(30,61,47,.05);
  --lift-2: 0 2px 4px rgba(30,61,47,.07), 0 12px 28px rgba(30,61,47,.08);
  --lift-3: 0 4px 8px rgba(30,61,47,.08), 0 28px 64px rgba(30,61,47,.13);

  /* Text that is pine on paper and cream on a dark field. Split out from --pine
     because --pine is also a BACKGROUND (buttons, the dark bands, the chart
     bars) — flipping one token for both roles turns the CTA banner cream and
     the text on it invisible. One token per job. */
  --head: var(--pine);
  --ledger: rgba(30,61,47,0.10);

  /* FONT TOKENS — these were missing.
     Eight rules in this file already referenced var(--mono) / var(--serif),
     including the Product and Resources dropdown headings and the "See how it
     works →" links. With the token undefined, font-family resolved to nothing
     and those elements silently fell back to the inherited sans — so the
     mega-menu on the homepage was set in a different face from the identical
     menu on how-it-works.html, which defines these tokens in its own
     stylesheet. Nothing errors when a custom property is missing; the
     declaration is simply dropped, which is why this survived so long.

     Values copied verbatim from how-it-works.html so the two menus are now
     the same object, not two things that resemble each other. */
  --sans:'IBM Plex Sans',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  --serif:'Fraunces',Georgia,'Times New Roman',serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,monospace;
  /* Light text that sits on a DARK surface — the pine bands, the CTA banner,
     the statement, a filled primary button. Split out from --cream after
     --cream was repointed to the dark page background and took every one of
     these with it: near-black text on a near-black block, invisible.

     --cream is a SURFACE token. --on-dark is a TEXT token. They happened to be
     the same color in the light theme, which is exactly why one was doing
     both jobs and why it broke the moment the themes diverged.

     This value is deliberately NOT overridden in the dark block below. There
     is no theme in which text on a dark band should stop being light. */
  --on-dark:#F4EFE1;
}

/* ===========================================================================
   DARK THEME
   Opt-in via <html data-theme="dark">; the toggle in the draft page sets it.
   Not wired to prefers-color-scheme — that decision belongs to whoever ships
   this, and auto-switching a page under review makes it harder to compare.

   Surfaces invert; brand hues don't. Pine stays pine, but rust and brass are
   lifted a couple of steps because both sit around 4:1 on cream and drop under
   3:1 on a dark field, which is below AA for body-size text.
   =========================================================================== */
html[data-theme="dark"]{
  --cream:#0E1D16;          /* page — pine pushed almost to black */
  --paper-card:#16291F;     /* raised card */
  --pine-soft:#1E3B2C;      /* tinted chip/fill */
  --ink:#E9E4D6;            /* body text */
  --grey:#9AA79F;
  --head:#F1EDE1;
  --rust:#D9744C;           /* +2 steps for contrast on dark */
  --rust-soft:#3A2018;
  --brass:#D7A544;
  --brass-soft:#3A2E15;
  --line:rgba(233,228,214,0.14);
  --ledger:rgba(233,228,214,0.055);
  /* Shadows do almost nothing on a dark page — depth has to come from the
     surface being lighter than the page, plus a hairline. These stay only to
     ground the edges of the largest cards. */
  --lift-1:0 1px 2px rgba(0,0,0,.35);
  --lift-2:0 2px 6px rgba(0,0,0,.4);
  --lift-3:0 8px 28px rgba(0,0,0,.45);
}
/* Tells the browser to render its OWN widgets dark: scrollbars, the caret,
   select menus, date pickers, autofill shading. Without it a dark page keeps
   a white scrollbar and light form chrome, which is the giveaway that a dark
   theme was painted on rather than declared. */
html{color-scheme:light dark;}
html[data-theme="dark"]{color-scheme:dark;}
html:not([data-theme]){color-scheme:light;}
*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
html,body{margin:0;padding:0;}
body{
  background-color:var(--cream);
  background-image: linear-gradient(var(--cream) 0, var(--cream) 27px, var(--ledger) 28px);
  background-size: 100% 28px;
  color:var(--ink);
  font-family:'IBM Plex Sans', system-ui, sans-serif;
  font-size:16px;
  line-height:1.5;
}
img{max-width:100%; display:block;}
a{color:var(--head);}
.container{max-width:1080px; margin:0 auto; padding:0 24px;}

h1,h2,h3{font-family:'Fraunces', serif; font-weight:600; font-optical-sizing:auto; color:var(--head); margin:0 0 16px 0; letter-spacing:-0.01em;}
h1{font-size:clamp(34px, 5.2vw, 56px); line-height:1.05;}
h2{font-size:clamp(26px, 3.4vw, 38px); line-height:1.1;}
h3{font-size:20px; line-height:1.25;}
p{margin:0 0 16px 0;}
.lede{font-size:18px; line-height:1.6; color:var(--ink); max-width:56ch;}
.tag{
  font-family:'IBM Plex Mono', monospace; font-size:12px; letter-spacing:0.12em;
  color:var(--rust); text-transform:uppercase; font-weight:600; margin:0 0 10px 0; display:block;
}
.rule{height:3px; background:var(--rust); width:64px; margin:0 0 20px 0; border:none;}

/* ---- buttons ---- */
.btn{
  display:inline-block; font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:15px;
  padding:13px 24px; border:1.5px solid var(--pine); border-radius:var(--radius);
  text-decoration:none; cursor:pointer; letter-spacing:0.01em; transition:background .15s ease, color .15s ease;
}
.btn-primary{background:var(--pine); color:var(--on-dark); border-color:var(--pine);}
.btn-primary:hover{background:var(--pine-dk); border-color:var(--pine-dk);}
.btn-ghost{background:transparent; color:var(--head); border-color:var(--pine);}
.btn-ghost:hover{background:var(--pine-soft);}
.btn-lg{padding:16px 30px; font-size:16px;}

/* ---- nav ---- */
.site-nav{
  position:sticky; top:0; z-index:20; background:var(--cream);
  border-bottom:1.5px solid var(--line);
}
.site-nav .container{display:flex; align-items:center; justify-content:space-between; height:76px;}
.brand{display:flex; align-items:center; gap:11px; text-decoration:none;}
/* The mark is the traced vector — same artwork as support/assets/brasswell-mark-black.svg
   and the two Cowork-built pages, not a CSS-drawn "B". The B inherits `color`;
   the two rules beneath it are always brand rust, in every variant. See
   BRAND-ASSETS.md: drawing the B with font-family:Georgia/Fraunces silently
   changes shape on machines without that font installed — the vector doesn't. */
.mark{display:block; height:34px; width:auto; color:#1F4436; flex:none;}
.mark .rule{fill:#C0552A;}
.brand-word{font-family:'Fraunces', serif; font-weight:600; font-size:19px; color:var(--head);}
.nav-links{display:flex; align-items:center; gap:26px; list-style:none; margin:0; padding:0;}
/* Product / Pricing / Resources must be ONE rule.
   This selector used to be `.nav-links a` alone. Pricing is an <a> and got the
   mono, uppercase, 12.5px treatment; Product and Resources are <button
   class="mega-trigger"> and got nothing — .mega-trigger sets `font:inherit`,
   so they fell back to the body sans at 16px. Three nav items, two typefaces,
   two sizes, and therefore two different baselines. That is what the uneven
   line was.

   The button also needs the same padding-bottom and transparent bottom border
   as the anchors, or the hover underline sits at a different height and the
   items are a pixel and a half out of vertical alignment even once the type
   matches. */
/* Product / Pricing / Resources — ONE identical box.
   Two of the three are <button class="mega-trigger">, one is an <a>, and they
   were computing different heights for a reason that is invisible in the
   markup: the canonical mega block sets `font:inherit` on .mega-trigger, and
   `font` is a SHORTHAND — it resets line-height along with the family and
   size. The anchors were on 1.4, the buttons fell back to the inherited 1.5.
   Different line-height, different box height, different baseline, three items
   that never quite sat on the same line.

   Rather than out-specify that shorthand and hope nothing else re-enters, the
   box is now stated outright: a fixed height, a fixed line-height, and the
   same flex centering on all three. Nothing here is left to compute. */
/* Flex ONLY where it is needed, which is the desktop nav row.
   The <li class="has-mega"> contains both the trigger and the .mega panel.
   Above 861px .has-mega is position:static, so .mega is absolutely positioned
   and out of flex flow — display:flex here does nothing but align the trigger.
   At 860px and below .mega becomes position:static, and a flex li lays it out
   in a ROW beside the button: three columns of menu content crushed into the
   space next to a trigger, every line on top of the next. That is the
   overlapping text — not the breakpoints, and not the hover underline.
   Below the breakpoint the li goes back to normal block flow, where a static
   panel stacks under its trigger the way the mobile design intends. */
@media (min-width:861px){
  .nav-links > li{display:flex; align-items:center;}
}
/* DIRECT CHILDREN ONLY — and this is the whole bug.
   `.nav-links a` is a descendant selector, so it matched every anchor inside
   the list, including the .mega-link anchors nested three levels down inside
   the dropdown panel. Each of those got height:20px, line-height:20px and
   box-sizing:content-box — one line tall. A menu link is two lines: an
   uppercase title and a wrapped description. So the text overflowed a 20px box
   while the next link sat 20px below it, and the second line of every
   description landed underneath the following link's title.
   The box never overlapped, which is why measuring getBoundingClientRect on
   these anchors reported "no overlap" while the panel plainly looked broken —
   the boxes are 20px apart as designed; it is the TEXT that escapes them. */
.nav-links > li > a,
.nav-links > li > .mega-trigger{
  display:inline-flex; align-items:center; gap:5px;
  height:20px; line-height:20px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.08em; text-transform:uppercase;
  font-weight:600; color:var(--ink); text-decoration:none;
  border-bottom:1.5px solid transparent; padding:0 0 2px; margin:0;
  background:none; border-left:0; border-right:0; border-top:0;
  box-sizing:content-box; vertical-align:middle;
  transition:color .15s,border-color .15s;
}
/* One shared baseline. The <li> wrappers are flex items of differing intrinsic
   height (a button box vs an inline anchor), so aligning the ROW is not enough
   — the items themselves have to sit on the same line. */
.nav-links > li > a:hover, .nav-links > li > a[aria-current="page"]{color:var(--rust); border-color:var(--rust);}
.nav-cta{display:flex; align-items:center; gap:18px;}
/* the "Log in" link sits in .nav-cta, not inside a .nav-links list, so it needs its
   own rule to match the other nav links' look — .nav-links a alone won't reach it. */
.login-link{
  font-family:'IBM Plex Mono', monospace; font-size:12.5px; letter-spacing:0.08em; text-transform:uppercase;
  font-weight:600; color:var(--ink); text-decoration:none; border-bottom:1.5px solid transparent; padding-bottom:2px;
  transition:color .15s ease, border-color .15s ease;
}
.login-link:hover{color:var(--rust); border-color:var(--rust);}

/* ---- mobile nav toggle ---- */
.nav-toggle{
  display:none; align-items:center; justify-content:center; width:40px; height:40px;
  background:transparent; border:1.5px solid var(--pine); border-radius:8px; color:var(--head);
  cursor:pointer; padding:0; flex:none;
}
.nav-panel{display:contents;}

/* ---- breadcrumb ---- */
.breadcrumb{font-family:'IBM Plex Mono', monospace; font-size:12px; letter-spacing:0.06em; color:var(--grey); padding:18px 0 0 0;}
.breadcrumb a{color:var(--grey); text-decoration:none; border-bottom:1px solid transparent;}
.breadcrumb a:hover{color:var(--rust); border-color:var(--rust);}
.breadcrumb .sep{margin:0 8px; opacity:.6;}
.breadcrumb [aria-current]{color:var(--ink); font-weight:600;}

/* ---- hero ---- */
/* The reference puts a soft wash of color behind the hero and lets the product
   card float on top of it. Same idea here in brand colors: a wide, very low
   opacity brass-into-pine bloom rising from the bottom of the hero, sitting
   under everything and reading as light rather than as a shape. It is
   deliberately weak — at full strength this stops being depth and starts being
   a gradient background, which is a different and worse-looking decision. */
.hero{padding:64px 0 56px 0; position:relative; isolation:isolate;}
.hero::before{content:""; position:absolute; z-index:-1; inset:auto 0 -8% 0; height:78%;
  background:
    radial-gradient(58% 78% at 22% 100%, rgba(184,134,43,.20), transparent 70%),
    radial-gradient(64% 84% at 76% 96%, rgba(30,61,47,.16), transparent 72%);
  filter:blur(6px); pointer-events:none;}
.hero-grid{display:grid; grid-template-columns:1.1fr 0.9fr; gap:48px; align-items:center;}
.hero-art{
  aspect-ratio:4/3; background:var(--paper-card); border-radius:16px; border:1.5px solid var(--line);
  display:flex; align-items:center; justify-content:center; padding:32px;
  box-shadow:var(--lift-3);
}
.hero-actions{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:8px;}
.hero-micro{font-size:13px; color:var(--grey); margin-top:14px;}

/* ---- feature panel (lettuce's overlapping "everything you need" band) ---- */
/* Dark panels get the glow treatment from the reference's FAQ/CTA sections — a
   brass bloom rising from the lower edge so the flat pine block has a light
   source instead of being a rectangle of color. */
.feature-panel{background:var(--pine); border-radius:20px; padding:44px 40px 40px 40px; margin:8px 0 44px 0; color:var(--on-dark);
  box-shadow:var(--lift-3); position:relative; overflow:hidden;}
.feature-panel::before{content:""; position:absolute; inset:auto 0 -30% 0; height:70%;
  background:radial-gradient(50% 100% at 50% 100%, rgba(184,134,43,.22), transparent 68%);
  pointer-events:none;}
.feature-panel > *{position:relative;}
.feature-panel h2{color:var(--on-dark); text-align:center; margin-bottom:32px;}
.feature-grid{display:grid; grid-template-columns:repeat(4, 1fr); gap:18px;}
.feature-card{background:var(--pine-dk); border-radius:14px; padding:22px 20px; border:1px solid rgba(244,239,225,0.12);}
.feature-icon{
  width:38px; height:38px; border-radius:9px; background:var(--rust); display:flex; align-items:center; justify-content:center;
  margin-bottom:16px;
}
.feature-icon svg{width:20px; height:20px; stroke:var(--cream); fill:none;}
.feature-card h3{color:var(--on-dark); font-size:17px; margin-bottom:8px;}
.feature-card p{color:#cfd9d2; font-size:14px; margin:0;}

/* ---- alternating sections ---- */
.split{display:grid; grid-template-columns:1fr 1fr; gap:56px; align-items:center; padding:38px 0;}
.split.reverse .split-art{order:2;}
.split.reverse .split-copy{order:1;}
.split-art{
  aspect-ratio:4/3; border-radius:16px; border:1.5px solid var(--line); display:flex; align-items:center; justify-content:center; padding:36px;
}
.split-art.pine{background:var(--pine-soft);}
.split-art.rust{background:var(--rust-soft);}
.split-art.brass{background:var(--brass-soft);}
.split hr.rule{margin-top:4px;}

/* ---- dual CTA (Buy now / Start trial) ----
   Both buttons point at #waitlist until launch — see the data-launch-href
   note in HANDOFF.md for the one-line swap when app.brasswell.app goes live. */
.dual-cta{display:flex; gap:14px; flex-wrap:wrap; align-items:center; margin:22px 0 10px 0;}
.dual-cta-note{font-size:13px; color:var(--grey); margin:0 0 8px 0;}

/* ---- trial timeline (3-step) ---- */
.trial-steps{display:grid; grid-template-columns:repeat(3, 1fr); gap:20px; margin:28px 0 8px 0;}
.trial-step{
  background:var(--paper-card); border:1.5px solid var(--line); border-radius:14px; padding:22px 20px;
  position:relative;
}
.trial-step .step-num{
  font-family:'IBM Plex Mono', monospace; font-size:12px; letter-spacing:0.1em; text-transform:uppercase;
  font-weight:600; color:var(--rust); display:block; margin-bottom:8px;
}
.trial-step h3{margin-bottom:6px; font-size:17px;}
.trial-step p{font-size:14px; color:var(--ink); margin:0;}

/* ---- decision guide (Core vs Pro, "which is right for you") ---- */
.decision-grid{display:grid; grid-template-columns:1fr 1fr; gap:24px; margin:8px 0 40px 0;}
.decision-card{border:1.5px solid var(--line); border-radius:14px; padding:24px; background:var(--paper-card);}
.decision-card.pro-pick{border-color:var(--brass);}
.decision-card h3{font-size:18px; margin-bottom:12px;}
.decision-card ul{list-style:none; margin:0; padding:0;}
.decision-card li{
  font-size:14.5px; padding:6px 0 6px 22px; position:relative; color:var(--ink);
}
.decision-card li::before{content:"→"; position:absolute; left:0; color:var(--rust); font-weight:700;}

/* ---- comparison cards ("why BrassWell") ---- */
.compare-grid{display:grid; grid-template-columns:repeat(3, 1fr); gap:20px; margin:28px 0 8px 0;}
.compare-card{background:var(--paper-card); border:1.5px solid var(--line); border-radius:14px; padding:24px;}
.compare-card .versus{
  font-family:'IBM Plex Mono', monospace; font-size:11.5px; letter-spacing:0.08em; text-transform:uppercase;
  color:var(--grey); font-weight:600; margin-bottom:10px; display:block;
}
.compare-card h3{font-size:17px; margin-bottom:8px;}
.compare-card p{font-size:14px; color:var(--ink); margin:0;}

/* ---- pricing cards ---- */
.pricing-grid{display:grid; grid-template-columns:1fr 1fr; gap:28px; margin:36px 0 56px 0;}
.price-card{
  background:var(--paper-card); border:1.5px solid var(--line); border-radius:16px; padding:32px;
  display:flex; flex-direction:column;
}
.price-card.pro{border-color:var(--brass); box-shadow:0 0 0 1px var(--brass);}
.price-card .badge{
  align-self:flex-start; font-family:'IBM Plex Mono', monospace; font-size:11px; letter-spacing:0.08em;
  text-transform:uppercase; font-weight:600; padding:4px 10px; border-radius:999px; margin-bottom:16px;
}
.price-card.core .badge{background:var(--pine-soft); color:var(--head);}
.price-card.pro .badge{background:var(--brass-soft); color:var(--brass);}
.price-amount{font-family:'Fraunces', serif; font-size:40px; font-weight:600; color:var(--head); margin:0 0 2px 0;}
.price-period{font-size:14px; color:var(--grey); margin-bottom:20px;}
.price-list{list-style:none; margin:0 0 24px 0; padding:0;}
.price-list li{padding:8px 0; border-top:1px solid var(--line); font-size:14.5px;}
.price-list li:first-child{border-top:none;}

/* ---- FAQ ---- */
/* The second dark block, matching the reference's near-black FAQ. Each question
   becomes a raised row on the dark field rather than a rule-separated list —
   which also gives the open/closed state somewhere to go visually. */
.faq-dark{background:var(--pine-dk); border-radius:20px; padding:52px 40px 46px;
  margin:8px 0 0; box-shadow:var(--lift-3);
  position:relative; overflow:hidden; isolation:isolate;}
.faq-dark::before{content:""; position:absolute; z-index:-1; inset:auto 0 -40% 0; height:85%;
  background:radial-gradient(46% 100% at 50% 100%, rgba(184,134,43,.18), transparent 70%);
  pointer-events:none;}
.faq-dark h2{color:var(--on-dark);}
@media (max-width:640px){ .faq-dark{padding:38px 20px 32px;} }

.faq{max-width:760px; margin:0 auto;}
.faq details{border-top:1.5px solid var(--line); padding:18px 0;}
.faq details:last-child{border-bottom:1.5px solid var(--line);}
.faq summary{
  font-family:'Fraunces', serif; font-size:18px; font-weight:600; color:var(--head);
  cursor:pointer; list-style:none; display:flex; justify-content:space-between; align-items:center; gap:16px;
}
.faq summary::-webkit-details-marker{display:none;}
.faq summary::after{content:"+"; font-family:'IBM Plex Sans',sans-serif; font-size:22px; color:var(--rust); flex:none;
  transition:transform .2s ease;}
.faq details[open] summary::after{content:"–";}
.faq .faq-a{margin-top:12px; color:var(--ink); font-size:15px; max-width:64ch;}

/* Dark-field overrides. Rows instead of rules: a bordered card per question,
   lifting slightly on hover and brightening when open. */
.faq-dark .faq details{border:1px solid rgba(244,239,225,.13); border-radius:12px;
  padding:16px 20px; margin-bottom:10px; background:rgba(244,239,225,.04);
  transition:background .18s ease, border-color .18s ease, transform .18s ease;}
.faq-dark .faq details:last-child{border-bottom:1px solid rgba(244,239,225,.13); margin-bottom:0;}
.faq-dark .faq details:hover{background:rgba(244,239,225,.07); transform:translateY(-1px);}
.faq-dark .faq details[open]{background:rgba(244,239,225,.08); border-color:rgba(184,134,43,.42);}
.faq-dark .faq summary{color:var(--on-dark);}
.faq-dark .faq summary::after{color:var(--brass);}
.faq-dark .faq .faq-a{color:#cfd9d2;}

/* ---- CTA banner ---- */
.cta-banner{
  background:var(--pine); border-radius:20px; padding:52px 40px; text-align:center; color:var(--on-dark); margin:64px 0;
  box-shadow:var(--lift-3); position:relative; overflow:hidden; isolation:isolate;
}
.cta-banner::before{content:""; position:absolute; z-index:-1; inset:auto 0 -40% 0; height:88%;
  background:radial-gradient(46% 100% at 50% 100%, rgba(184,134,43,.26), transparent 70%);
  pointer-events:none;}
.cta-banner h2{color:var(--on-dark);}
.cta-banner p{color:#cfd9d2; max-width:56ch; margin:0 auto 28px auto;}
.cta-banner .rule{margin:0 auto 20px auto;}

/* ---- footer ---- */
/* One footer, one band, on every page.
   It was four different footers — three column sets, two bottom lines and a
   support page with its own — which is the same drift the header had. It also
   sat on the page background, so on a dark page it simply continued the last
   section rather than closing the document. A footer should read as the floor:
   a step DOWN in value, not another band at the same level. */
footer.site-footer{border-top:1.5px solid var(--line);
  background:var(--footer-bg);
  padding:64px 0 56px; margin-top:72px;}
.footer-fine{margin:40px 0 0; padding-top:22px;
  border-top:1.5px solid var(--line);
  font-size:12.5px; line-height:1.6; color:var(--grey);
  /* One line, and short enough to stay one line. The old version ran to two
     and spent them re-stating things the pages already say: that BrassWell
     does not file your taxes (implied by "estimates, not tax advice"), and
     that Plaid covers US institutions (now stated where bank connections are
     actually explained). What survives is what belongs in a footer — the
     copyright, the reservation of rights, the standing disclaimer, and the
     currency. */
  text-wrap:pretty;}
:root{--footer-bg:#F1EBDC;}
.footer-grid{display:grid; grid-template-columns:1.4fr repeat(3, 1fr); gap:32px;}
/* h3, not h4. These are the footer's column labels and they used to be h4,
   which put an h2 -> h4 jump at the bottom of nine pages. A screen reader's
   heading list is a table of contents: a level skipped reads as a missing
   section, so the reader hunts for the h3 that was never there. Nothing about
   the appearance changes — the size is set here, not by the tag. The
   mega-menu's h4s are left alone; they sit under the nav, not in the document
   outline, and are a different use. */
.footer-col h3{
  font-family:'IBM Plex Mono', monospace; font-size:12px; letter-spacing:0.1em; text-transform:uppercase;
  color:var(--grey); margin:0 0 14px 0; font-weight:600;
}
.footer-col ul{list-style:none; margin:0; padding:0;}
.footer-col li{margin-bottom:10px;}
.footer-col a{color:var(--ink); text-decoration:none; font-size:14px;}
.footer-col a:hover{color:var(--rust);}
.footer-brand p{color:var(--grey); font-size:13px; max-width:32ch;}
.footer-legal{
  margin-top:44px; padding-top:24px; border-top:1px solid var(--line);
  display:flex; justify-content:space-between; flex-wrap:wrap; gap:12px;
  font-size:12px; color:var(--grey); font-family:'IBM Plex Mono', monospace; letter-spacing:0.04em;
}
.footer-legal a{color:var(--grey);}

/* ---- sticky mobile CTA ---- */
.sticky-cta{
  display:none; position:fixed; left:0; right:0; bottom:0; z-index:30;
  background:var(--cream); border-top:1.5px solid var(--pine); padding:12px 16px;
  box-shadow:0 -6px 18px rgba(20,43,33,0.12);
}
.sticky-cta .btn{width:100%; text-align:center;}

/* ---- misc page shells ---- */
.page-hero{padding:48px 0 8px 0;}
.center{text-align:center;}
/* 40+40 between adjacent sections was 80px of dead air, and .switcher and
   .feature-panel each added a further 72px bottom margin on top of it.
   28px reads as deliberate breathing room rather than a gap. */
.section{padding:28px 0;}
.error-shell{min-height:70vh; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:40px 24px;}
.error-shell .code{font-family:'IBM Plex Mono', monospace; color:var(--rust); font-size:14px; letter-spacing:0.12em; text-transform:uppercase; margin-bottom:10px;}
.legal-body h2{font-size:20px; margin-top:36px;}
.legal-body p, .legal-body li{color:var(--ink); font-size:15px;}
.legal-note{
  background:var(--rust-soft); border:1.5px solid var(--rust); border-radius:12px; padding:18px 20px; margin:24px 0 40px 0;
  font-size:14px;
}

@media (max-width: 860px){
  .hero-grid{grid-template-columns:1fr;}
  .hero-art{order:-1;}
  .feature-grid{grid-template-columns:1fr 1fr;}
  .split{grid-template-columns:1fr;}
  .split.reverse .split-art{order:-1;}
  .pricing-grid{grid-template-columns:1fr;}
  .trial-steps{grid-template-columns:1fr;}
  .decision-grid{grid-template-columns:1fr;}
  .compare-grid{grid-template-columns:1fr;}
  .dual-cta{flex-direction:column; align-items:stretch;}
  .dual-cta .btn{text-align:center;}
  .footer-grid{grid-template-columns:1fr 1fr;}
  .site-nav .container{position:relative;}
  .nav-toggle{display:inline-flex;}
  .nav-panel{
    display:none; position:absolute; top:76px; left:0; right:0; z-index:19;
    background:var(--cream); border-bottom:1.5px solid var(--line);
    box-shadow:0 12px 24px rgba(20,43,33,0.12);
    flex-direction:column; align-items:stretch; gap:20px; padding:20px 24px 26px 24px;
  }
  .nav-panel.open{display:flex;}
  .nav-links{flex-direction:column; align-items:flex-start; gap:16px;}
  .nav-cta{flex-direction:column; align-items:stretch; gap:12px;}
  .nav-cta .btn{width:100%; text-align:center;}
  .login-link{align-self:flex-start;}
  .sticky-cta{display:block;}
  body{padding-bottom:70px;}
}
@media (max-width: 520px){
  .feature-grid{grid-template-columns:1fr;}
  .footer-grid{grid-template-columns:1fr;}
}

/* ---------------------------------------------------------------------------
   PRODUCT VISUALS (added 2026-08-21)
   Replaces the generic line-icon placeholders that sat in .hero-art and the
   three .split-art panels. These are drawn UI — stylized representations of
   real BrassWell screens — not photographs and not real screenshots. Every
   figure shown is illustrative sample data, never a real user's. When actual
   product screenshots exist, these are the blocks to swap out.
   Built from the same tokens as the rest of the sheet so they can't drift
   from the brand.
--------------------------------------------------------------------------- */

/* --- shared device chrome --- */
.ui{
  width:100%; background:var(--paper-card); border-radius:12px;
  border:1.5px solid rgba(30,61,47,0.22); overflow:hidden;
  box-shadow:0 12px 28px rgba(30,61,47,0.13), 0 2px 6px rgba(30,61,47,0.06);
  font-family:'IBM Plex Sans', system-ui, sans-serif;
}
.ui-bar{
  display:flex; align-items:center; gap:6px; padding:9px 12px;
  background:var(--pine); border-bottom:1.5px solid rgba(30,61,47,0.22);
}
.ui-dot{width:8px; height:8px; border-radius:50%; background:rgba(244,239,225,0.34);}
.ui-bar b{
  margin-left:8px; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:10.5px; letter-spacing:.07em; text-transform:uppercase;
  color:rgba(244,239,225,0.86); font-weight:600;
}
.ui-body{padding:16px 16px 18px 16px;}
.ui-label{
  display:block; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:9.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--grey); margin-bottom:4px; font-weight:600;
}
.ui-big{
  font-family:'Fraunces', serif; font-weight:600; font-size:30px;
  line-height:1; color:var(--head); letter-spacing:-0.01em;
}
.ui-head{display:flex; align-items:flex-start; justify-content:space-between; gap:12px;}
.ui-pill{
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:10px; font-weight:600;
  letter-spacing:.04em; padding:4px 8px; border-radius:999px;
  background:var(--pine-soft); color:var(--head); border:1px solid rgba(30,61,47,0.16);
  white-space:nowrap;
}

/* --- hero: month view with the irregular-income bars + bucket split --- */
.ui-bars{display:flex; align-items:flex-end; gap:4px; height:56px; margin:16px 0 6px 0;}
.ui-bars i{flex:1; background:var(--pine); border-radius:2px 2px 1px 1px; display:block;}
.ui-bars i.lo{background:rgba(30,61,47,0.20);}
.ui-months{
  display:flex; gap:4px; margin-bottom:16px;
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:8px; color:var(--grey);
}
.ui-months span{flex:1; text-align:center;}
.ui-split{
  display:flex; height:26px; border-radius:6px; overflow:hidden;
  border:1px solid rgba(30,61,47,0.18);
}
.ui-split i{display:block; height:100%;}
.ui-legend{
  display:flex; flex-wrap:wrap; gap:4px 12px; margin-top:10px;
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:9px; color:var(--grey);
}
.ui-legend span{display:flex; align-items:center; gap:5px;}
.ui-legend i{width:7px; height:7px; border-radius:2px; flex:0 0 auto;}
.ui-note{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin-top:14px; padding:10px 12px; border-radius:8px;
  background:var(--rust-soft); border:1px solid rgba(181,75,42,0.22);
}
.ui-note span{font-size:12px; color:var(--ink);}
.ui-note b{font-family:'Fraunces', serif; font-size:16px; color:var(--rust); font-weight:600;}

/* --- split panels: each art tile holds one small UI card --- */
.split-art .ui{max-width:340px;}

/* tax: quarter-by-quarter set-aside */
.ui-rows{margin-top:14px;}
.ui-row{
  display:flex; align-items:center; gap:10px; padding:7px 0;
  border-top:1px solid var(--line); font-size:12px;
}
.ui-row:first-child{border-top:0;}
.ui-row .q{
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:9.5px;
  letter-spacing:.06em; color:var(--grey); width:26px; flex:0 0 auto; font-weight:600;
}
.ui-row .track{flex:1; height:6px; border-radius:3px; background:rgba(30,61,47,0.10); overflow:hidden;}
.ui-row .track i{display:block; height:100%; background:var(--pine); border-radius:3px;}
.ui-row .amt{
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:11px;
  color:var(--ink); width:52px; text-align:right; flex:0 0 auto;
}
.ui-row.due .track i{background:var(--rust);}
.ui-row.due .amt{color:var(--rust); font-weight:600;}

/* invoice: line items + paid stamp */
.ui-inv{display:flex; align-items:baseline; justify-content:space-between; font-size:12px; padding:6px 0;}
.ui-inv + .ui-inv{border-top:1px solid var(--line);}
.ui-inv span{color:var(--grey);}
.ui-inv b{font-family:'IBM Plex Mono', ui-monospace, monospace; font-weight:500; color:var(--ink);}
.ui-total{
  display:flex; align-items:baseline; justify-content:space-between;
  margin-top:10px; padding-top:10px; border-top:1.5px solid rgba(30,61,47,0.22);
}
.ui-total span{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:9.5px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--grey); font-weight:600;}
.ui-total b{font-family:'Fraunces', serif; font-size:20px; color:var(--head); font-weight:600;}
.ui-stamp{
  display:inline-block; margin-top:12px; padding:5px 10px; border-radius:6px;
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:9.5px; font-weight:600;
  letter-spacing:.1em; text-transform:uppercase;
  color:#2F7A5E; background:rgba(47,122,94,0.10); border:1px solid rgba(47,122,94,0.30);
}

/* goal: ring + target */
.ui-goal{display:flex; align-items:center; gap:16px; margin-top:4px;}
.ui-ring{position:relative; width:82px; height:82px; flex:0 0 auto;}
.ui-ring svg{width:100%; height:100%; transform:rotate(-90deg);}
.ui-ring .val{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-family:'Fraunces', serif; font-weight:600; font-size:19px; color:var(--head);
}
.ui-goal .meta b{
  display:block; font-family:'Fraunces', serif; font-size:19px; color:var(--head);
  font-weight:600; line-height:1.1; margin-bottom:2px;
}
.ui-goal .meta span{font-size:11.5px; color:var(--grey); line-height:1.4; display:block;}

@media (max-width:860px){
  .ui-big{font-size:26px;}
  .split-art .ui{max-width:100%;}
}

/* ---------------------------------------------------------------------------
   BUSINESS HEALTH RINGS + MOTION (added 2026-08-21)
   The rings are the real product's signature screen — three dials answering
   the three questions a self-employed person otherwise does in their head
   (Pace / Margin / Tax cover), with a one-word grade in the corner. Colors
   and behavior are taken from components/dashboard/HealthRings.tsx and
   app/tokens.generated.css so the site and the app can't drift apart.
   Ring colors are the APP's tokens (brighter pine #1f6650, sienna #c2622b),
   deliberately, so what the page shows is what a user actually sees.
--------------------------------------------------------------------------- */
:root{
  --app-pine:#1f6650; --app-rust:#b23a2f; --app-brass:#b8862b; --app-sienna:#c2622b;
}

/* --- motion primitives --- */
[data-motion]{opacity:0; transform:translateY(20px);
  transition:opacity .6s cubic-bezier(.22,.8,.36,1), transform .6s cubic-bezier(.22,.8,.36,1);}
[data-motion].in{opacity:1; transform:none;}
.ui-bars i[data-h]{height:0; transition:height .8s cubic-bezier(.22,.8,.36,1);}
.ui-split i[data-w], .ui-row .track i[data-w]{width:0; transition:width .9s cubic-bezier(.22,.8,.36,1);}
.dial-arc{transition:stroke-dasharray 1.1s cubic-bezier(.22,.8,.36,1);}

/* --- health rings --- */
.health-head{display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:4px;}
.health-grade{font-family:'IBM Plex Sans', system-ui, sans-serif; font-size:13px; font-weight:600;
  color:var(--app-pine);}
.dials{display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin:14px 0 4px 0;}
.dial{text-align:center;}
.dial .ring{position:relative; width:100%; max-width:92px; margin:0 auto; aspect-ratio:1;}
.dial svg{width:100%; height:100%; transform:rotate(-90deg); display:block;}
.dial .mid{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-family:'Fraunces', serif; font-weight:600; font-size:17px; color:var(--head); line-height:1;}
.dial .nm{display:block; margin-top:8px; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:9px; letter-spacing:.1em; text-transform:uppercase; color:var(--grey); font-weight:600;}
.dial .sub{display:block; margin-top:3px; font-size:10.5px; color:var(--grey); line-height:1.3;}
.collections{display:flex; align-items:center; gap:8px; margin-top:14px; padding:9px 11px;
  border-radius:8px; background:var(--brass-soft); border:1px solid rgba(184,134,43,0.30);
  font-size:11.5px; color:var(--ink);}
.collections b{font-family:'IBM Plex Mono', ui-monospace, monospace; font-weight:600; color:var(--app-brass);}

/* --- rating strip (Wave/Monarch put social proof right at the hero) --- */
.rating{display:flex; align-items:center; gap:9px; margin-bottom:18px;}
.rating .stars{color:var(--brass); font-size:13px; letter-spacing:2px;}
.rating span{font-size:12.5px; color:var(--grey);}

@media (max-width:520px){
  .dials{gap:4px;}
  .dial .mid{font-size:14px;}
  .dial .sub{display:none;}
}

/* Reduced motion: everything simply arrives finished. */
@media (prefers-reduced-motion: reduce){
  [data-motion]{opacity:1; transform:none; transition:none;}
  .ui-bars i[data-h], .ui-split i[data-w], .ui-row .track i[data-w], .dial-arc{transition:none;}
  /* The chart's staged reveals. motion.js's settle() still adds .in, so these
     reach their end state — this just removes the travel getting there. */
  .bar .stack, .bar .tax, .bar .mo, .salary-line, .salary-tag, .split-seg,
  .split-key div{transition:none !important;}
  .bar .tax{transform:none;}
  .bar .mo, .salary-tag, .split-key div{opacity:1; transform:none;}
  .salary-line{opacity:1; transform:scaleX(1);}
}

/* ---------------------------------------------------------------------------
   CROSS-PLATFORM BAND (added 2026-08-21)
   Same beat Monarch plays with "On every device, always in sync" — but shown
   rather than asserted: the same three health dials rendered once in a phone
   frame and once in a browser frame. Only iOS and web are claimed, because
   only iOS and web exist (App Store record + app.brasswell.app).
--------------------------------------------------------------------------- */
.devices{background:var(--pine); border-radius:20px; padding:48px 40px; margin:8px 0 72px 0;
  box-shadow:var(--lift-3); position:relative; overflow:hidden; isolation:isolate;
  color:var(--on-dark);}
.devices::before{content:""; position:absolute; z-index:-1; inset:auto 0 -35% 0; height:80%;
  background:radial-gradient(52% 100% at 62% 100%, rgba(184,134,43,.22), transparent 70%);
  pointer-events:none;}
.devices h2{color:var(--on-dark); margin-bottom:12px;}
.devices .lede{color:#cfd9d2; max-width:52ch; margin-bottom:0;}
.devices-grid{display:grid; grid-template-columns:1fr 1fr; gap:44px; align-items:center;}
@media (max-width:860px){.devices-grid{grid-template-columns:1fr; gap:32px;} .devices{padding:36px 24px;}}
.devices .tag{background:rgba(244,239,225,0.12); color:var(--on-dark); border-color:rgba(244,239,225,0.24);}
.device-note{display:flex; gap:10px; align-items:flex-start; margin-top:22px; font-size:14px; color:#cfd9d2;}
.device-note b{color:var(--on-dark); font-weight:600;}




/* ---------------------------------------------------------------------------
   HEALTH-DIAL MOTION (extended 2026-08-21)
   The sweep alone reads as "a chart loaded." These add the sense that the
   dashboard is live: the arc draws, then the ring gives one soft pulse, and
   the grade word fades in after the dials have settled — the same order of
   events a user sees when the real screen mounts.
--------------------------------------------------------------------------- */
.dial .ring{transition:transform .5s cubic-bezier(.34,1.56,.64,1);}
.dial-arc{
  transition:stroke-dasharray 1.2s cubic-bezier(.22,.8,.36,1),
             filter .5s ease;
}
[data-motion].in .dial-arc{filter:drop-shadow(0 0 3px rgba(184,134,43,0.28));}
[data-motion].in .dial:nth-child(1) .ring{animation:dialPop .6s cubic-bezier(.34,1.56,.64,1) 1.05s both;}
[data-motion].in .dial:nth-child(2) .ring{animation:dialPop .6s cubic-bezier(.34,1.56,.64,1) 1.19s both;}
[data-motion].in .dial:nth-child(3) .ring{animation:dialPop .6s cubic-bezier(.34,1.56,.64,1) 1.33s both;}
@keyframes dialPop{
  0%{transform:scale(1);} 45%{transform:scale(1.045);} 100%{transform:scale(1);}
}
.health-grade{opacity:0; transition:opacity .5s ease .95s;}
[data-motion].in .health-grade{opacity:1;}
/* the collections strip slides in last — it's the "one more thing" line */
.collections{opacity:0; transform:translateY(6px);
  transition:opacity .5s ease 1.35s, transform .5s cubic-bezier(.22,.8,.36,1) 1.35s;}
[data-motion].in .collections{opacity:1; transform:none;}

@media (prefers-reduced-motion: reduce){
  .dial .ring, [data-motion].in .dial .ring{animation:none !important; transition:none;}
  .health-grade, .collections{opacity:1 !important; transform:none !important; transition:none;}
  .dial-arc{transition:none;}
}

/* ---------------------------------------------------------------------------
   BRAND MARK — 2026-08-21, final.
   This is the shipped asset (Brasswell Social Kit/Logo Files/
   brasswell-icon-mark-pine-1024.png), not a CSS re-creation. Earlier attempts
   to redraw it kept getting details wrong — the tile is SQUARE, not rounded,
   and the two rust rules sit inside the tile beneath a cream serif B.
   Using the real file removes the whole class of drift.
--------------------------------------------------------------------------- */
/* The mark is a solid pine tile with the B and rules drawn on it, so the corner
   treatment is ours to set in CSS rather than baked into the PNG.
   border-radius:0 was wrong — a hard square was the one shape on the page with
   no curve at all, next to buttons at 10px, cards at 14px and pills at 999px.
   23% is the iOS-icon superellipse ratio: ~8.7px at 38px, ~6.9px at 30px, so
   the curve reads identically at every size it's used without a second rule. */
.mark{width:38px; height:38px; flex:none; display:block; border-radius:23%;}
.footer-brand .mark{width:30px; height:30px;}

/* ---------------------------------------------------------------------------
   DEVICE SHELLS — MacBook + iPhone (2026-08-21)
   Drawn hardware, so the same dashboard can be shown on both surfaces without
   waiting on photography. Proportions follow the real thing: 16:10 laptop
   display, ~9:19.5 phone display with a Dynamic-Island pill, and the laptop's
   wedge base sitting wider than the lid with a centered thumb notch.
--------------------------------------------------------------------------- */
.device-stage{position:relative; padding-bottom:26px;}

/* ---- MacBook ---- */
.laptop{width:100%; max-width:430px;}
.laptop-lid{background:#141517; border-radius:11px 11px 3px 3px; padding:11px 11px 15px 11px;
  box-shadow:0 22px 44px rgba(0,0,0,0.34), inset 0 0 0 1px rgba(255,255,255,0.07);}
.laptop-cam{width:4px; height:4px; border-radius:50%; background:#2c2e31; margin:0 auto 8px auto;}
.laptop-screen{background:var(--paper-card); border-radius:3px; overflow:hidden; aspect-ratio:16/10;}
.laptop-base{position:relative; height:11px; width:116%; margin-left:-8%;
  background:linear-gradient(#c9ccd1 0%, #a9adb4 42%, #7e838b 100%);
  border-radius:0 0 11px 11px; box-shadow:0 8px 16px rgba(0,0,0,0.26);}
.laptop-base::after{content:""; position:absolute; left:50%; transform:translateX(-50%); top:0;
  width:64px; height:5px; background:#8b9097; border-radius:0 0 6px 6px;}

/* ---- iPhone: overlaps the laptop's lower-left corner ---- */
.iphone{position:absolute; left:-6px; bottom:0; width:132px; background:#141517;
  border-radius:26px; padding:5px; box-shadow:0 20px 40px rgba(0,0,0,0.42),
  inset 0 0 0 1px rgba(255,255,255,0.09);}
/* side buttons */
.iphone::before{content:""; position:absolute; left:-2px; top:56px; width:2px; height:22px;
  background:#2a2c2f; border-radius:2px 0 0 2px;}
.iphone::after{content:""; position:absolute; right:-2px; top:66px; width:2px; height:34px;
  background:#2a2c2f; border-radius:0 2px 2px 0;}
.iphone-screen{position:relative; background:var(--paper-card); border-radius:22px; overflow:hidden;
  aspect-ratio:9/19.5; padding:22px 9px 10px 9px;}
.iphone-island{position:absolute; top:7px; left:50%; transform:translateX(-50%);
  width:44px; height:13px; background:#0b0c0d; border-radius:99px;}
.iphone-home{position:absolute; bottom:5px; left:50%; transform:translateX(-50%);
  width:42px; height:3px; background:rgba(30,61,47,0.28); border-radius:99px;}

@media (max-width:860px){
  .laptop{max-width:100%;}
  .iphone{width:112px; left:-4px;}
}
@media (max-width:430px){.iphone{display:none;}}

/* dials scale down inside each shell */
.laptop-screen .dials{gap:6px; margin:10px 0 0 0;}
.laptop-screen .dial .mid{font-size:13px;}
.laptop-screen .dial .nm{font-size:7.5px; margin-top:5px;}
.laptop-screen .dial .sub{display:none;}
.laptop-screen .ui-label{font-size:8.5px;}
.laptop-screen .health-grade{font-size:11px;}
.laptop-screen .ui-note{margin-top:10px; padding:7px 9px;}
.laptop-screen .ui-note span{font-size:9.5px;}
.laptop-screen .ui-note b{font-size:13px;}
.laptop-body{padding:12px 13px;}
.laptop-url{display:flex; align-items:center; gap:5px; padding:5px 7px; margin-bottom:9px;
  background:#eeeade; border-radius:5px;
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:7.5px; color:var(--grey);}
.laptop-url i{width:5px; height:5px; border-radius:50%; background:rgba(30,61,47,0.22); display:block;}

.iphone-screen .dials{grid-template-columns:1fr; gap:7px; margin:8px 0 0 0;}
.iphone-screen .dial{display:flex; align-items:center; gap:8px; text-align:left;}
.iphone-screen .dial .ring{width:34px; max-width:34px; flex:none;}
.iphone-screen .dial .mid{font-size:9px;}
.iphone-screen .dial .nm{margin-top:0; font-size:7px;}
.iphone-screen .dial .sub{display:none;}
.iphone-screen .ui-label{font-size:7px;}
.iphone-screen .health-grade{font-size:8.5px;}

/* ---------------------------------------------------------------------------
   COOKIE BANNER — mirrors the one already live on brasswell.app
   (Brasswell Waitlist Site/worker.js, COOKIE_BANNER). Same pine bar, same
   "Got it" dismissal, same localStorage ack key so a visitor who dismissed it
   on the waitlist page isn't asked twice.
   COPY DIFFERS DELIBERATELY: the live banner says "cookie-free analytics",
   which was true of Cloudflare Web Analytics alone. These pages now also load
   GA4, which sets its own _ga cookies, so the wording here says so.
--------------------------------------------------------------------------- */
#bw-cookie-notice{display:none; position:fixed; left:0; right:0; bottom:0; z-index:100;
  background:var(--pine); color:var(--on-dark); font-family:'IBM Plex Sans', system-ui, sans-serif;
  box-shadow:0 -6px 20px rgba(0,0,0,0.18);}
#bw-cookie-notice .inner{max-width:900px; margin:0 auto; padding:16px 24px;
  display:flex; flex-wrap:wrap; align-items:center; gap:14px 24px;}
#bw-cookie-notice p{margin:0; font-size:13.5px; line-height:1.55; flex:1; min-width:240px;
  color:var(--on-dark);}
#bw-cookie-notice a{color:var(--on-dark); text-decoration:underline;}
#bw-cookie-ok{flex:none; border:1.5px solid var(--on-dark); background:transparent; color:var(--on-dark);
  padding:9px 20px; font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:13px;
  cursor:pointer; border-radius:6px;}
#bw-cookie-ok:hover{background:var(--cream); color:var(--pine);}

/* ---------------------------------------------------------------------------
   SECTION VARIETY (2026-08-21)
   The page had one shape — heading + grid of equal boxes — repeated eight
   times, which is what made it read like a spreadsheet. These give the scroll
   a changing rhythm, the way Bench alternates full-bleed panels with quotes
   and stat rows, and Monarch swaps a four-card grid for one tabbed panel:
     .statement  — full-width, huge type, no box at all
     .statband   — three counting numbers on pine, full-bleed
     .switcher   — one big panel you tab through, instead of four small cards
--------------------------------------------------------------------------- */

/* --- statement: a beat of pure type, no container --- */
/* Dark block. The reference alternates light and near-black bands so the page
   has a rhythm you can feel while scrolling rather than one continuous field of
   paper. This is the natural one to darken: it's a single sentence stating the
   problem, so it wants to read as a pause, and inverting it makes the pause
   physical. Brass glow from the lower edge, same light source as the other
   dark bands. */
.statement{padding:84px 40px 78px; text-align:center;
  background:var(--pine-dk); border-radius:20px; margin:56px 0 8px;
  box-shadow:var(--lift-3); position:relative; overflow:hidden; isolation:isolate;}
.statement::before{content:""; position:absolute; z-index:-1; inset:auto 0 -45% 0; height:95%;
  background:radial-gradient(44% 100% at 50% 100%, rgba(184,134,43,.24), transparent 70%);
  pointer-events:none;}
.statement p{font-family:'Fraunces', serif; font-weight:600; font-size:clamp(26px,3.7vw,42px);
  line-height:1.22; color:var(--on-dark); max-width:19ch; margin:0 auto; letter-spacing:-0.01em;}
.statement p em{font-style:normal; position:relative; white-space:nowrap;}
.statement p em::after{content:""; position:absolute; left:-.05em; right:-.05em; bottom:.06em;
  height:.36em; background:rgba(184,134,43,.42); z-index:-1; transform:scaleX(0);
  transform-origin:left; transition:transform .9s .35s cubic-bezier(.22,.8,.36,1);}
.statement.in p em::after, [data-motion].in .statement p em::after{transform:scaleX(1);}
.statement .by{display:block; margin-top:22px; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:11.5px; letter-spacing:.12em; text-transform:uppercase; color:rgba(244,239,225,.62);}

/* --- stat band: three numbers, full-bleed pine --- */
.statband{background:var(--pine-dk); border-radius:20px; padding:40px 32px; margin:0 0 72px 0;
  box-shadow:var(--lift-3); position:relative; overflow:hidden; isolation:isolate;}
.statband::before{content:""; position:absolute; z-index:-1; inset:auto 0 -50% 0; height:100%;
  background:radial-gradient(40% 100% at 50% 100%, rgba(184,134,43,.20), transparent 70%);
  pointer-events:none;}
.statband-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:24px; text-align:center;}
@media (max-width:700px){.statband-grid{grid-template-columns:1fr; gap:28px;} .statband{padding:32px 22px;}}
.statband b{display:block; font-family:'Fraunces', serif; font-weight:600;
  font-size:clamp(34px,4.6vw,50px); line-height:1; color:var(--on-dark); margin-bottom:8px;}
.statband span{font-size:13.5px; color:#a9bcb0; line-height:1.45; display:block; max-width:26ch;
  margin:0 auto;}
.statband .sep{width:34px; height:2px; background:var(--rust); margin:0 auto 14px auto;}

/* --- switcher: one panel at a time --- */
.switcher{margin:0 0 44px 0;}
.switch-tabs{display:flex; gap:8px; flex-wrap:wrap; justify-content:center; margin-bottom:26px;}
.switch-tab{font-family:'IBM Plex Sans', sans-serif; font-size:14px; font-weight:600;
  padding:10px 18px; border-radius:999px; border:1.5px solid var(--line);
  background:var(--paper-card); color:var(--grey); cursor:pointer; transition:all .18s;}
.switch-tab:hover{border-color:var(--pine); color:var(--head);}
.switch-tab[aria-selected="true"]{background:var(--pine); border-color:var(--pine); color:var(--on-dark);}
.switch-panels{position:relative; background:var(--paper-card); border:1.5px solid var(--line);
  border-radius:16px; padding:34px; min-height:250px;}
@media (max-width:760px){.switch-panels{padding:24px;}}
.switch-panel{display:none; grid-template-columns:1fr 1fr; gap:36px; align-items:center;}
.switch-panel[data-active="true"]{display:grid; animation:panelIn .45s cubic-bezier(.22,.8,.36,1) both;}
@media (max-width:760px){.switch-panel[data-active="true"]{grid-template-columns:1fr; gap:24px;}}
@keyframes panelIn{from{opacity:0; transform:translateY(10px);} to{opacity:1; transform:none;}}
.switch-panel h3{font-size:24px; margin-bottom:10px;}
.switch-panel p{color:var(--ink); font-size:15.5px; margin-bottom:14px;}
.switch-panel .micro{font-size:13px; color:var(--grey); margin:0;}
.switch-art{background:var(--pine-soft); border:1.5px solid var(--line); border-radius:12px;
  padding:22px; display:flex; align-items:center; justify-content:center; min-height:190px;}

/* receipt-scan mini visual */
.scan{width:100%; max-width:210px;}
.scan-paper{background:var(--paper-card); border:1.5px solid var(--line-2, rgba(30,61,47,0.22));
  border-radius:6px; padding:12px 13px; position:relative; overflow:hidden;}
.scan-line{height:6px; background:rgba(30,61,47,0.13); border-radius:3px; margin-bottom:7px;}
.scan-line.w60{width:60%;} .scan-line.w40{width:40%;} .scan-line.w80{width:80%;}
.scan-beam{position:absolute; left:0; right:0; height:34px; top:-34px;
  background:linear-gradient(180deg, rgba(184,134,43,0) 0%, rgba(184,134,43,0.26) 50%, rgba(184,134,43,0) 100%);
  animation:beam 2.6s cubic-bezier(.5,0,.5,1) infinite;}
@keyframes beam{0%{top:-34px;} 60%{top:100%;} 100%{top:100%;}}
.scan-out{margin-top:10px; background:var(--pine); color:var(--on-dark); border-radius:7px;
  padding:9px 11px; display:flex; align-items:center; justify-content:space-between; gap:10px;}
.scan-out span{font-size:11px; opacity:.82;}
.scan-out b{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:13px;}

@media (prefers-reduced-motion: reduce){
  .scan-beam{animation:none; display:none;}
  .switch-panel[data-active="true"]{animation:none;}
  .statement p em::after{transform:scaleX(1); transition:none;}
}

/* ---------------------------------------------------------------------------
   RESOURCES / ARTICLES (added 2026-08-21)
   The site had nowhere to publish, which meant none of the keyword work in
   BrassWell-SEO-Audit-2026-08-21.md could actually happen — a 3-page site
   can't rank for informational queries. This is the template that unblocks it.
--------------------------------------------------------------------------- */
.post-list{display:grid; gap:16px; margin-top:28px;}
.post-card{display:block; text-decoration:none; background:var(--paper-card);
  border:1.5px solid var(--line); border-radius:var(--radius); padding:24px;
  transition:border-color .15s, transform .15s;}
.post-card:hover{border-color:var(--pine); transform:translateY(-2px);}
.post-card .kicker{display:block; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--rust);
  font-weight:600; margin-bottom:9px;}
.post-card h3{margin-bottom:8px; font-size:21px;}
.post-card p{margin:0 0 12px; color:var(--grey); font-size:14.5px;}
.post-card .meta{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:11px;
  color:var(--grey); letter-spacing:.04em;}

/* --- article body --- */
.article{max-width:720px; margin:0 auto; padding:0 24px;}
.article-head{padding:44px 0 8px;}
.article-head h1{font-size:clamp(30px,4.4vw,44px); line-height:1.1; margin-bottom:14px;}
.article-meta{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:11.5px;
  letter-spacing:.06em; color:var(--grey); text-transform:uppercase;}
.article-body{font-size:17px; line-height:1.72; color:var(--ink); padding-bottom:20px;}
.article-body h2{font-size:26px; margin:38px 0 12px;}
.article-body h3{font-size:19px; margin:28px 0 8px;}
.article-body p{margin:0 0 18px;}
.article-body ul, .article-body ol{margin:0 0 18px; padding-left:22px;}
.article-body li{margin-bottom:9px;}
.article-body strong{color:var(--head); font-weight:600;}
/* The one fact a page turns on. Rust rather than plain bold, so a scanner
   finds it without reading the paragraph.

   Deliberately a class and not a rule on the first strong in a lede: exactly
   one sentence per article earns this, chosen by a person. Made automatic it
   would fire on whichever strong happened to come first, and a highlight that
   appears everywhere highlights nothing.

   --rust is already defined per theme (#B54B2A light, #D9744C dark), so this
   needs no dark override and cannot drift out of contrast when the palette
   moves. Measured 4.94:1 and 5.73:1 against their own page backgrounds. */
.article-body strong.flag{color:var(--rust);}

/* ---------------------------------------------------------------------------
   GUIDE TABLE OF CONTENTS + DATA TABLE
   Both new with the personal-trainer rewrite. The TOC exists because a
   2,400-word page with eight sections is a page people scan rather than read,
   and because anchor links are what Google uses to build the jump-to links
   under a result. The table exists because a three-column "thing / yes or no /
   the catch" grid is the shape that wins an answer box, and because the
   deductions list was the highest-volume query we were covering in prose.
   --------------------------------------------------------------------------- */
.guide-toc{margin:26px 0 34px; padding:18px 22px 14px;
  background:var(--pine-soft); border-radius:var(--radius);
  border:1px solid var(--line);}
.guide-toc .toc-title{margin:0 0 8px; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--grey);}
.guide-toc ol{margin:0; padding-left:20px;}
.guide-toc li{margin-bottom:4px; font-size:15.5px;}
.guide-toc a{color:var(--head); text-decoration:none;
  border-bottom:1px solid transparent;}
.guide-toc a:hover{border-bottom-color:currentColor;}

/* Tables overflow on a phone. Wrapping rather than shrinking the type keeps
   the figures legible; a table nobody can read is worse than one they scroll. */
.table-wrap{overflow-x:auto; margin:0 0 22px;
  -webkit-overflow-scrolling:touch;}
.guide-table{width:100%; border-collapse:collapse; font-size:15px;
  line-height:1.5; min-width:520px;}
.guide-table caption{caption-side:top; text-align:left; padding:0 0 10px;
  font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--grey);}
.guide-table th, .guide-table td{padding:11px 14px 11px 0; text-align:left;
  vertical-align:top; border-bottom:1px solid var(--line);}
.guide-table thead th{font-weight:600; color:var(--head); white-space:nowrap;
  border-bottom-width:1.5px;}
.guide-table tbody td:first-child{color:var(--head); font-weight:500;}
.guide-table tbody td:nth-child(2){white-space:nowrap; font-family:'IBM Plex Mono', ui-monospace, monospace;
  font-size:13px; color:var(--grey);}
.guide-table tbody tr:last-child td{border-bottom:0;}
@media (max-width:620px){
  .guide-table{font-size:14px;}
  .guide-table th, .guide-table td{padding:9px 11px 9px 0;}
}
.article-body a{color:var(--head); text-underline-offset:2px;}
.article-lede{font-size:19px; line-height:1.6; color:var(--ink); margin-bottom:26px;
  padding-bottom:22px; border-bottom:1.5px solid var(--line);}

/* callouts */
.callout{background:var(--pine-soft); border-left:3px solid var(--pine);
  border-radius:0 var(--radius) var(--radius) 0; padding:18px 20px; margin:0 0 22px;}
.callout p{margin:0; font-size:15.5px;}
.callout.warn{background:var(--rust-soft); border-left-color:var(--rust);}
.callout b{display:block; font-family:'Fraunces', serif; font-size:16px; color:var(--head);
  margin-bottom:5px;}
.callout.warn b{color:var(--rust);}

/* worked example */
.calc{background:var(--paper-card); border:1.5px solid var(--line-2, rgba(30,61,47,0.22));
  border-radius:var(--radius); padding:20px 22px; margin:0 0 24px;}
.calc-row{display:flex; justify-content:space-between; gap:16px; padding:9px 0;
  border-top:1px solid var(--line); font-size:15px;}
.calc-row:first-of-type{border-top:0;}
.calc-row span{color:var(--grey);}
.calc-row b{font-family:'IBM Plex Mono', ui-monospace, monospace; font-weight:500; color:var(--ink);
  white-space:nowrap;}
.calc-row.total{border-top:1.5px solid var(--pine); margin-top:5px; padding-top:12px;}
.calc-row.total span{color:var(--head); font-weight:600;}
.calc-row.total b{color:var(--head); font-weight:600; font-size:17px;}
.calc h4{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:10.5px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--rust); margin:0 0 12px; font-weight:600;}

.article-cta{background:var(--pine); border-radius:16px; padding:32px; margin:36px 0 10px;
  text-align:center; color:var(--on-dark);}
.article-cta h3{color:var(--on-dark); margin-bottom:8px;}
.article-cta p{color:#cfd9d2; font-size:15px; margin:0 auto 18px; max-width:44ch;}

.disclaimer{font-size:13.5px; color:var(--grey); line-height:1.6; padding:20px 0 0;
  border-top:1.5px solid var(--line); margin-top:34px;}

/* --- comparison table (added 2026-08-21) --- */
.cmp{width:100%; border-collapse:collapse; margin:0 0 8px; font-size:15px;}
.cmp th, .cmp td{text-align:left; padding:13px 14px; border-bottom:1px solid var(--line);
  vertical-align:top;}
.cmp thead th{font-family:'IBM Plex Mono', ui-monospace, monospace; font-size:10.5px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--rust); font-weight:600;
  border-bottom:1.5px solid var(--line-2, rgba(30,61,47,0.22));}
.cmp tbody th{font-weight:600; color:var(--head); width:32%;}
.cmp td.yes{color:var(--head);} .cmp td.no{color:var(--grey);}
.cmp-wrap{overflow-x:auto; background:var(--paper-card); border:1.5px solid var(--line);
  border-radius:var(--radius); padding:6px 18px 12px; margin-bottom:24px;}
@media (max-width:640px){.cmp{font-size:13.5px;} .cmp th, .cmp td{padding:10px 8px;}}

/* ---------- breadcrumb --------------------------------------------------- */
.crumbs{font-family:var(--mono); font-size:11.5px; letter-spacing:.05em; color:var(--grey);
  padding:18px 0 0;}
.crumbs a{color:var(--grey); text-decoration:none;}
.crumbs a:hover{color:var(--rust); text-decoration:underline;}
.crumbs span{margin:0 7px; opacity:.5;}

/* ---------- device mockups ----------------------------------------------- */
/* Drawn in CSS rather than shipped as images: the frames stay crisp at any
   density, restyle with the brand, and — the reason that matters — the screen
   inside is live markup, so the dashboard it shows is the real component,
   not a screenshot that goes stale the next time the UI moves. */
.devices{position:relative; display:flex; align-items:flex-end; justify-content:center;
  gap:0; padding-bottom:8px;}

/* MacBook: lid, screen, then the tapered base below it. */
.laptop{flex:1 1 auto; max-width:560px; min-width:0;}
.laptop .lid{background:#1b2620; border-radius:14px 14px 4px 4px; padding:11px 11px 12px;
  box-shadow:0 22px 48px rgba(30,61,47,.20);}
.laptop .screen{background:var(--cream); border-radius:6px; overflow:hidden;
  aspect-ratio:16/10.4;}
.laptop .screen .ui{border:0; border-radius:0; box-shadow:none; height:100%;}
.laptop .base{height:11px; background:linear-gradient(#c9cdc8,#9aa39c);
  border-radius:0 0 9px 9px; margin:0 auto; width:112%; max-width:none;
  position:relative; left:-6%;}
.laptop .base::after{content:""; position:absolute; top:0; left:50%; transform:translateX(-50%);
  width:88px; height:5px; background:#7f877f; border-radius:0 0 5px 5px;}

/* iPhone: overlaps the laptop's lower-right corner, the way a product shot
   stacks a phone in front of a desktop. */
.phone{flex:0 0 176px; margin-left:-58px; margin-bottom:26px; position:relative; z-index:2;}
.phone .body{background:#1b2620; border-radius:26px; padding:7px;
  box-shadow:0 18px 40px rgba(30,61,47,.24);}
.phone .screen{background:var(--cream); border-radius:20px; overflow:hidden;
  aspect-ratio:9/19.2; position:relative;}
.phone .notch{position:absolute; top:0; left:50%; transform:translateX(-50%);
  width:52px; height:15px; background:#1b2620; border-radius:0 0 9px 9px; z-index:3;}
.phone .pscreen{padding:26px 12px 14px; height:100%; box-sizing:border-box;}
.phone .p-title{font-family:var(--serif); font-size:12.5px; font-weight:600;
  color:var(--head); margin:0 0 2px;}
.phone .p-sub{font-family:var(--mono); font-size:8.5px; letter-spacing:.07em;
  text-transform:uppercase; color:var(--grey); margin:0 0 12px;}
.phone .p-rings{display:flex; gap:7px; margin-bottom:13px;}
.phone .p-rings .dial{flex:1;}
.phone .p-rings .ring{width:100%; aspect-ratio:1;}
.phone .p-rings .dial-num{font-size:10px;}
.phone .p-rings .dial-cap{font-size:7px; letter-spacing:.04em;}
.phone .p-row{display:flex; justify-content:space-between; align-items:center;
  padding:7px 0; border-top:1px solid var(--line); font-size:9.5px; color:var(--ink);}
.phone .p-row b{font-family:var(--mono); font-weight:600;}
.phone .p-row .in{color:var(--head);} .phone .p-row .out{color:var(--rust);}

@media (max-width:820px){
  .devices{flex-direction:column; align-items:center; gap:0;}
  .laptop{width:100%; max-width:460px;}
  .phone{margin:-40px 0 0 200px; flex-basis:150px;}
}
@media (max-width:520px){
  .phone{margin:-34px 0 0 120px; flex-basis:132px;}
}

/* ---------- alternating photo + feature rows ----------------------------- */
.photo-row{display:grid; grid-template-columns:1fr 1fr; gap:52px; align-items:center;
  padding:20px 0;}
/* `order` only applies to direct grid children. The founder row wraps its image
   and caption in a div, so a selector aimed at .photo-media silently did
   nothing and both rows rendered image-left. Target the first child instead —
   works whether the column is a bare .photo-media or a wrapper. */
.photo-row.reverse > *:first-child{order:2;}
.photo-media{border-radius:14px; overflow:hidden; border:1.5px solid var(--line);
  background:var(--pine-soft); aspect-ratio:4/3; position:relative;
  box-shadow:var(--lift-2);}
.photo-media img{width:100%; height:100%; object-fit:cover; display:block;}
/* The empty state. A gray box with no explanation reads as a broken image; this
   says what belongs here and who has to put it there. */
.photo-media.pending{display:flex; align-items:center; justify-content:center;
  text-align:center; padding:28px;
  background:repeating-linear-gradient(45deg, var(--pine-soft) 0 12px, #dce8e1 12px 24px);}
.photo-media.pending p{margin:0; font-family:var(--mono); font-size:11.5px; line-height:1.7;
  letter-spacing:.03em; color:var(--head); max-width:34ch;}
.photo-media.pending p b{display:block; font-size:12.5px; margin-bottom:6px;
  text-transform:uppercase; letter-spacing:.1em; color:var(--rust);}

.photo-copy h2,
.photo-copy h3{font-family:var(--serif); font-size:clamp(22px,2.6vw,29px); line-height:1.15;
  color:var(--head); margin:0 0 18px; letter-spacing:-.01em;}
.feat-list{list-style:none; margin:0; padding:0;}
.feat-list li{padding:0 0 16px; font-size:15.5px; line-height:1.6; color:var(--ink);}
.feat-list li b{display:block; color:var(--head); font-weight:600; margin-bottom:2px;}
@media (max-width:820px){
  .photo-row{grid-template-columns:1fr; gap:26px;}
  .photo-row.reverse > *:first-child{order:0;}
}

/* Founder caption. Sits under the photo rather than over it: an overlay would
   fight the image and vanish on a light frame. The rust rule ties it to the
   section-marker motif used elsewhere, so it reads as part of the page rather
   than a badge stuck on. */
/* ---- wide photo band ----------------------------------------------------
   A single 16:10 image spanning the column, used as a breath between the
   feature rows and the income chart. It exists because that transition was
   otherwise 76px of empty page, and because the library already had a picture
   that argues the next section's point: a man at the end of a job, about to be
   paid an amount that is nothing like last month's. */
/* A LETTERBOX, not a picture. At 16:10 across the full column this ran ~645px
   tall — taller than the hero, taller than the chart, the single biggest thing
   on the page. A man on a tailgate is a transition between two arguments, not
   the argument, so he gets a 3:1 strip at 720px: same job, roughly a third of
   the height. object-position keeps his face in frame as the crop tightens. */
.photo-band{margin:8px auto 0; max-width:720px;}
.photo-band .photo-media{aspect-ratio:3/1;}
.photo-band .photo-media img{object-position:50% 42%;}
.photo-band .photo-credit{max-width:60ch;}
@media (max-width:820px){ .photo-band .photo-media{aspect-ratio:2/1;} }

.photo-credit{display:flex; gap:10px; align-items:flex-start; margin-top:12px;
  font-size:13.5px; line-height:1.5; color:var(--grey);}
.photo-credit::before{content:""; flex:none; width:3px; align-self:stretch;
  background:var(--rust); border-radius:2px;}
.photo-credit b{color:var(--head); font-weight:600;}
/* The honesty marker, sized to match the caption rather than shout over it.
   It has to stay visible — this photograph is AI-generated and BrassWell has
   no customers yet, so the line between "here is what the feature does" and
   "here is a customer saying it works" is the whole point of the wording. */
.photo-credit .cred-note{font-style:normal; display:block; margin-top:3px;
  font-family:'IBM Plex Mono', monospace; font-size:10.5px; letter-spacing:.07em;
  text-transform:uppercase; opacity:.62;}

/* ===========================================================================
   DATA VIZ — the irregular-income chart and the bucket split
   Added 2026-08-28.

   These exist because the central claim of the product ("most finance apps
   assume a steady paycheck; yours isn't") is an argument about SHAPE, and
   shape is the one thing prose is bad at. A bar chart of twelve uneven months
   against a flat salary line makes it in about a second.

   Built on the existing motion.js hooks (data-h, data-count) so they inherit
   the staggered reveal and the prefers-reduced-motion fallback for free —
   no new observer, no second animation system to keep in step.
   =========================================================================== */

.viz{background:var(--paper-card); border:1.5px solid var(--line); border-radius:16px;
  padding:30px 32px 26px; box-shadow:var(--lift-2);}
.viz-head{display:flex; justify-content:space-between; align-items:baseline;
  gap:20px; flex-wrap:wrap; margin-bottom:4px;}
.viz-title{font-family:var(--serif,'Fraunces',serif); font-weight:600; font-size:19px;
  color:var(--head); margin:0;}
.viz-note{font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--grey); margin:0;}
/* 28px, not 22. The hover value labels are positioned at top:-22px against the
   full-height .bar, so on any month they float clear above the plot box. With
   22px of margin they landed on the last line of this paragraph. */
.viz-sub{font-size:14px; color:var(--grey); margin:2px 0 28px; max-width:60ch;}

/* ---- irregular income bars ---------------------------------------------- */
.bars{position:relative; display:flex; align-items:flex-end; gap:8px; height:190px;
  padding-bottom:26px; border-bottom:1.5px solid var(--line);}
.bar{flex:1; position:relative; display:flex; flex-direction:column;
  justify-content:flex-end; height:100%; min-width:0;}
/* Two stacked pieces: what you keep, and what was never yours. The tax slice
   sits UNDER the kept portion so the eye reads it as coming off the bottom of
   the month, which is what actually happens. */
/* Overshoot easing — the bar rises past its value by a hair and settles back,
   which is what makes a growing bar feel like it has weight instead of like a
   div being resized. */
.bar .stack{width:100%; border-radius:5px 5px 0 0; overflow:hidden;
  display:flex; flex-direction:column; justify-content:flex-end;
  height:0; transition:height 1s cubic-bezier(.2,1.12,.32,1);}
/* The tax slice slides up out of the kept portion a beat after the bar lands,
   so you see the split happen rather than arriving pre-split. */
.bar .kept{background:var(--pine); flex:1 1 auto;}
.bar .tax{background:var(--brass); flex:none;
  transform:translateY(100%); transition:transform .55s cubic-bezier(.22,.85,.3,1) .5s;}
[data-motion].in .bar .tax{transform:translateY(0);}
/* Month labels fade up in sequence behind the bars. --i is set per bar in the
   markup so the delay is data, not twelve hand-written rules. */
.bar .mo{position:absolute; bottom:-22px; left:0; right:0; text-align:center;
  opacity:0; transform:translateY(4px);
  transition:opacity .4s ease, transform .4s ease;
  transition-delay:calc(0.35s + var(--i, 0) * 0.045s);
  font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.04em;
  color:var(--grey);}
[data-motion].in .bar .mo{opacity:1; transform:translateY(0);}
.bar:hover .stack{filter:brightness(1.08);}
/* The value only appears on hover — twelve permanent labels is noise, and the
   shape is the point, not the individual figures. */
.bar .val{position:absolute; top:-22px; left:50%; transform:translateX(-50%) translateY(4px);
  font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600; color:var(--head);
  background:var(--paper-card); padding:1px 5px; border-radius:4px; white-space:nowrap;
  opacity:0; transition:opacity .15s, transform .15s; pointer-events:none;}
.bar:hover .val, .bar:focus-within .val{opacity:1; transform:translateX(-50%) translateY(0);}

/* The salary line. Dashed, rust, drawn across the average — the thing every
   other finance app quietly assumes is your life. */
.salary-line{position:absolute; left:0; right:0; border-top:2px dashed var(--rust);
  opacity:0; transform:scaleX(.02); transform-origin:left;
  transition:opacity .3s ease .75s, transform .85s cubic-bezier(.22,.85,.3,1) .75s;}
/* motion.js flags the section it observes, not the card inside it, so the
   line keys off the section's shown state. One reveal system, not two. */
[data-motion].in .salary-line{opacity:1; transform:scaleX(1);}
/* Anchored LEFT, not right. The tag has an opaque background so it can sit on
   the dashed rule without the rule striking through the words — which means
   wherever it lands it also punches a hole in whatever bar is behind it. On the
   right that was November (71%), a tall bar with a caption stamped across it.
   Jan (34%) and Feb (21%) both sit below the 40% line, so the left end of the
   rule is the one patch of the plot with nothing behind it. */
.salary-tag{position:absolute; left:0; top:-19px; z-index:2;
  opacity:0; transition:opacity .35s ease 1.45s;
  font-family:'IBM Plex Mono',monospace;
  font-size:10px; letter-spacing:.05em; text-transform:uppercase; color:var(--rust);
  background:var(--paper-card); padding:0 6px 0 0;}
[data-motion].in .salary-tag{opacity:1;}

.viz-legend{display:flex; gap:20px; flex-wrap:wrap; margin-top:26px; font-size:13px;
  color:var(--grey);}
.viz-legend span{display:flex; align-items:center; gap:7px;}
.viz-legend i{width:11px; height:11px; border-radius:3px; flex:none; display:block;}
.viz-legend .k{background:var(--pine);} .viz-legend .t{background:var(--brass);}
.viz-legend .s{background:none; border-top:2px dashed var(--rust); height:0; width:16px;
  border-radius:0;}

/* ---- bucket split -------------------------------------------------------- */
.split-bar{display:flex; height:54px; border-radius:9px; overflow:hidden;
  border:1.5px solid var(--line); margin:6px 0 14px;}
.split-seg{width:0; transition:width 1s cubic-bezier(.2,1.06,.32,1);
  display:flex; align-items:center; justify-content:center; min-width:0;
  font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600;
  color:var(--on-dark); overflow:hidden; white-space:nowrap;}
.split-seg.tax{background:var(--brass);}
.split-seg.costs{background:var(--rust);}
.split-seg.save{background:var(--pine-soft); color:var(--head);}
.split-seg.keep{background:var(--pine);}
/* Four items, so the column count must divide four. auto-fit was choosing
   whatever fitted — three tracks around 500px, which strands the fourth.
   4 -> 2 -> 1 all divide cleanly; 3 never does. */
.split-key{display:grid; grid-template-columns:repeat(4,1fr); gap:14px;
  margin-top:18px;}
/* The four keys rise in sequence after the bar has finished splitting, so the
   order reads as consequence: the money divides, then you're told what each
   piece is. Arriving together would make them a legend; arriving in order
   makes them the explanation. */
.split-key div{border-top:2px solid var(--line); padding-top:10px;
  opacity:0; transform:translateY(8px);
  transition:opacity .45s ease, transform .45s cubic-bezier(.22,.85,.3,1);
  transition-delay:calc(0.75s + var(--i, 0) * 0.11s);}
[data-motion].in .split-key div{opacity:1; transform:translateY(0);}
.split-key b{display:block; font-family:'IBM Plex Mono',monospace; font-size:15px;
  color:var(--head); margin-bottom:2px;}
.split-key span{font-size:12.5px; color:var(--grey); line-height:1.45;}
.split-key div.tax{border-color:var(--brass);}
.split-key div.costs{border-color:var(--rust);}
.split-key div.save{border-color:var(--pine-mid,#2F7A5E);}
.split-key div.keep{border-color:var(--pine);}

@media (max-width:640px){
  .viz{padding:22px 18px 20px;}
  .bars{height:150px; gap:5px;}
  .bar .mo{font-size:9px;}
  .split-seg{font-size:10px;}
}

/* ---------------------------------------------------------------------------
   DARK THEME — surface corrections
   The token swap above handles most of the page. These are the rules that
   hardcoded a light-page assumption and can't be reached by a variable.
   --------------------------------------------------------------------------- */

/* Primary button. Pine on near-black is a button you can barely see, so the
   solid fill flips to brass — the brand's only light-on-dark-capable hue —
   with dark text on it. */
html[data-theme="dark"] .btn-primary,
html[data-theme="dark"] .cta-primary{
  background:var(--brass); color:#14210E; border-color:var(--brass);}
html[data-theme="dark"] .btn-primary:hover,
html[data-theme="dark"] .cta-primary:hover{
  background:#E7B558; border-color:#E7B558;}
html[data-theme="dark"] .btn-ghost{border-color:rgba(233,228,214,.32);}
html[data-theme="dark"] .btn-ghost:hover{background:rgba(233,228,214,.07);}
html[data-theme="dark"] .login-link{border-color:rgba(233,228,214,.28);}

/* Nav and menus sit slightly above the page rather than flush with it, so the
   sticky header separates from the content scrolling under it. */
html[data-theme="dark"] .site-nav{background:rgba(14,29,22,.88);
  backdrop-filter:saturate(140%) blur(10px);}

/* The already-dark bands. On a dark page a pine block against a near-black
   page has almost no separation, so they go one step LIGHTER than the page
   instead of darker — the inversion of what they do in light mode. The brass
   glow does more work here and is dialled up accordingly. */
html[data-theme="dark"] .feature-panel,
html[data-theme="dark"] .devices,
html[data-theme="dark"] .cta-banner,
html[data-theme="dark"] .statement,
html[data-theme="dark"] .statband,
html[data-theme="dark"] .faq-dark{
  background:#1B3226; border:1px solid rgba(233,228,214,.10);}
html[data-theme="dark"] .feature-card{background:rgba(10,20,15,.5);
  border-color:rgba(233,228,214,.10);}

/* Chart. Pine bars on a dark card vanish; the kept portion becomes the light
   value and tax stays brass, which also matches how the eye reads the split
   in light mode (solid mass = yours, warm accent = not yours). */
html[data-theme="dark"] .bar .kept{background:#5E9C7C;}
html[data-theme="dark"] .split-seg.keep{background:#5E9C7C; color:#0E1D16;}
html[data-theme="dark"] .split-seg.save{background:var(--pine-soft); color:var(--head);}
html[data-theme="dark"] .split-seg.tax{color:#20180A;}
html[data-theme="dark"] .split-key div.keep{border-color:#5E9C7C;}
html[data-theme="dark"] .viz-legend .k{background:#5E9C7C;}
html[data-theme="dark"] .bar .val{background:#20382B; border:1px solid rgba(233,228,214,.14);}

/* Photos carry their own light. Knock them back a touch so a bright daylight
   frame doesn't punch a hole in a dark page. */
html[data-theme="dark"] .photo-media img,
html[data-theme="dark"] .mega-feature .shot{filter:brightness(.92) saturate(.96);}

/* The statement's highlight swipe needs more presence against cream text. */
html[data-theme="dark"] .statement p em::after{background:rgba(215,165,68,.34);}



/* ===========================================================================
   DARK THEME — DEPTH PASS
   Added after review: "the whole site seems very flat."

   The diagnosis is that a dark theme built purely by swapping tokens ends up
   with two tones — page and card — repeated forty times, and drop shadows do
   almost nothing on a dark field because there is no light for them to remove.
   Depth on dark comes from four things instead, all of them here:

     1. a surface LADDER, so a card, a raised band and a chip are three
        different values rather than one
     2. an inset top highlight on every raised thing — the single most
        effective trick on dark; it reads as a lit top edge, which is how the
        eye decides something is in front
     3. texture, so large fields aren't a perfectly flat wash
     4. alternating band tone, so scrolling changes value instead of repeating
   =========================================================================== */

html[data-theme="dark"]{
  --s1:#0E1D16;   /* page */
  --s2:#16291F;   /* card */
  --s3:#1D3628;   /* raised band */
  --s4:#254433;   /* chip / control */
  /* The lit top edge. Applied to anything that should read as in front. */
  --edge: inset 0 1px 0 rgba(233,228,214,.09);
  --edge-strong: inset 0 1px 0 rgba(233,228,214,.14);
}

/* ---- 3. texture ----------------------------------------------------------
   Two layers over the whole page, both fixed so they don't scroll with the
   content and reveal themselves as a pattern: a fine SVG grain, and a very
   wide vertical wash that keeps the top of the page from being the same value
   as the bottom. Together they stop large dark areas reading as a flat fill.
   pointer-events:none so neither eats a click. */
/* body is isolated so the two overlays can sit at z-index:-1 — above the page
   background, below every piece of content — without touching a single child.
   The previous version set position/z-index on `body > *`, and because the
   :not() list contained an ID it outweighed .site-nav's own z-index:20 and
   knocked the sticky header down to 1. The mega-menu lives inside the nav's
   stacking context, so it inherited that 1 and got painted underneath any
   later section — which is why the dropdowns were disappearing behind the
   photographs. Isolation does the same job with no side effects. */
html[data-theme="dark"] body{isolation:isolate;}
html[data-theme="dark"] body::after{
  content:""; position:fixed; inset:0; z-index:-1; pointer-events:none;
  opacity:.55; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");}
html[data-theme="dark"] body::before{
  content:""; position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(120% 60% at 50% -10%, rgba(94,156,124,.10), transparent 60%),
    radial-gradient(90% 50% at 50% 108%, rgba(215,165,68,.07), transparent 65%);}

/* ---- stacking order, stated once so it can't drift -----------------------
   The dropdown has to clear everything on the page, in both themes. The photo
   sections were winning before because the nav had been demoted; these numbers
   put the question beyond doubt rather than relying on source order. */
.site-nav{z-index:900;}
.hero, .section, .split, .switcher, .devices, .statband, .statement,
.feature-panel, .cta-banner, .faq-dark{z-index:1;}
/* A photo lifting on hover must not lift over an open menu. */
.photo-media:hover, .post-card:hover, .mega-feature:hover{z-index:2;}

/* ---- 1 + 2. surfaces and lit edges --------------------------------------- */
html[data-theme="dark"] .viz,
html[data-theme="dark"] .switch-panels,
html[data-theme="dark"] .post-card,
html[data-theme="dark"] .cmp-wrap,
html[data-theme="dark"] .price-card{
  background:linear-gradient(180deg, #1A2E23 0%, var(--s2) 60%);
  border-color:rgba(233,228,214,.13);
  box-shadow:var(--edge), 0 10px 30px rgba(0,0,0,.35);}

/* ---- 4. alternating band tone --------------------------------------------
   The big blocks were all one value, which is most of why the scroll felt
   flat. Now they step: feature panel and devices sit at the raised tone, the
   statement and stat band go DEEPER than the page (a hole rather than a
   shelf), and the FAQ and CTA sit between. Value changes as you scroll. */
html[data-theme="dark"] .feature-panel,
html[data-theme="dark"] .devices{
  background:linear-gradient(168deg, #24413090 0%, var(--s3) 45%, #172C21 100%);
  border:1px solid rgba(233,228,214,.11);
  box-shadow:var(--edge-strong), 0 18px 44px rgba(0,0,0,.42);}

/* These two were written to sit DEEPER than the page — a hole rather than a
   shelf. That worked when the page was #0E1D16. It stopped working the moment
   the page itself dropped to #0A1710 for the Leolift look: "deeper" became
   "identical", the bands lost their edges entirely, and the numbers inside
   them read as text floating on nothing.

   There is no room below near-black, so the recession is now made with light
   instead of value: the panel is a step LIGHTER than the page, with a hard
   inner shadow across the top edge, which is what a recess actually looks
   like. Same intent, achievable palette. */
html[data-theme="dark"] .statement,
html[data-theme="dark"] .statband{
  background:linear-gradient(180deg, #14261C 0%, #101F17 100%);
  border:1px solid rgba(233,228,214,.09);
  box-shadow:inset 0 8px 18px -10px rgba(0,0,0,.85),
             inset 0 -1px 0 rgba(233,228,214,.06),
             0 1px 0 rgba(233,228,214,.05);}

html[data-theme="dark"] .faq-dark,
html[data-theme="dark"] .cta-banner{
  background:linear-gradient(180deg, #1B3226 0%, #142719 100%);
  border:1px solid rgba(233,228,214,.10);
  box-shadow:var(--edge), 0 18px 44px rgba(0,0,0,.4);}

/* A hairline of brand color across the top of each major band. Cheap, and it
   does more for separation than another 10% of shadow would. */
html[data-theme="dark"] .feature-panel::after,
html[data-theme="dark"] .devices::after,
html[data-theme="dark"] .cta-banner::after,
html[data-theme="dark"] .faq-dark::after{
  content:""; position:absolute; top:0; left:14%; right:14%; height:1px;
  background:linear-gradient(90deg, transparent, rgba(215,165,68,.55), transparent);
  pointer-events:none;}

html[data-theme="dark"] .feature-card{
  background:linear-gradient(180deg, rgba(233,228,214,.055), rgba(0,0,0,.22));
  border-color:rgba(233,228,214,.11);
  box-shadow:var(--edge);}

/* ---- pills and chips -----------------------------------------------------
   Every pill was a flat fill with a flat border. Each now gets a top-lit
   gradient, a brighter top edge and a shadow underneath, so it reads as a
   physical control instead of a colored rectangle. */
html[data-theme="dark"] .switch-tab{
  background:linear-gradient(180deg, var(--s4), #1B3327);
  border-color:rgba(233,228,214,.16); color:#C9D3CC;
  box-shadow:var(--edge), 0 2px 5px rgba(0,0,0,.3);}
html[data-theme="dark"] .switch-tab:hover{
  border-color:rgba(215,165,68,.5); color:var(--head);}
html[data-theme="dark"] .switch-tab[aria-selected="true"]{
  background:linear-gradient(180deg,#E0AE4E,#C99433);
  border-color:#E0AE4E; color:#16210C;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 3px 10px rgba(215,165,68,.28);}

html[data-theme="dark"] .btn-primary,
html[data-theme="dark"] .cta-primary{
  background:linear-gradient(180deg,#E2B052,#C79231);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32), 0 4px 14px rgba(215,165,68,.26);}
html[data-theme="dark"] .btn-ghost,
html[data-theme="dark"] .cta-secondary,
html[data-theme="dark"] .login-link{
  background:linear-gradient(180deg, rgba(233,228,214,.075), rgba(233,228,214,.02));
  box-shadow:var(--edge);}

/* Eyebrow chips are handled by the .pill--* roles further down, which give
   each section a color that means something. This rule only carries the
   shared spacing — it must NOT set a color, or its higher specificity
   (html[data-theme] .tag) would beat .pill--brass and .pill--pine and flatten
   every eyebrow back to one rust chip. */
html[data-theme="dark"] .tag{margin-bottom:14px;}
html[data-theme="dark"] .viz-note{
  padding:3px 9px; border-radius:999px; border:1px solid rgba(233,228,214,.14);
  background:rgba(233,228,214,.05);}
html[data-theme="dark"] .price-card.core .badge{
  background:linear-gradient(180deg, var(--s4), #1B3327);
  border:1px solid rgba(233,228,214,.14); box-shadow:var(--edge);}

/* ---- separation ----------------------------------------------------------
   The ledger rule and every hairline border were near-invisible at dark-mode
   opacity, so blocks ran together. Lifted, and the FAQ rows get their own lit
   edge so the stack reads as separate cards rather than one striped panel. */
html[data-theme="dark"]{ --line:rgba(233,228,214,.17); --ledger:rgba(233,228,214,.038); }
html[data-theme="dark"] .faq-dark .faq details{
  background:linear-gradient(180deg, rgba(233,228,214,.055), rgba(233,228,214,.018));
  border-color:rgba(233,228,214,.13); box-shadow:var(--edge);}
html[data-theme="dark"] .faq-dark .faq details[open]{
  background:linear-gradient(180deg, rgba(215,165,68,.10), rgba(233,228,214,.03));
  border-color:rgba(215,165,68,.42);
  box-shadow:var(--edge-strong), 0 6px 18px rgba(0,0,0,.3);}

html[data-theme="dark"] .photo-media,
html[data-theme="dark"] .mega-feature .shot{
  border-color:rgba(233,228,214,.16);}
html[data-theme="dark"] .photo-media{
  box-shadow:var(--edge), 0 14px 34px rgba(0,0,0,.42);}

html[data-theme="dark"] .site-nav{border-bottom-color:rgba(233,228,214,.13);}
html[data-theme="dark"]{--footer-bg:#0A1710;}
html[data-theme="dark"] footer.site-footer{border-top-color:rgba(233,228,214,.13);}
html[data-theme="dark"] .footer-fine{border-top-color:rgba(233,228,214,.10); color:#8E9A92;}

@media (prefers-reduced-motion: reduce){
  html[data-theme="dark"] body::after{opacity:.4;}
}

/* ===========================================================================
   PILL SYSTEM + MICRO-INTERACTIONS
   Added after review: "more variety with pills and some transitions."

   One base shape, four roles, so a chip's color tells you what kind of thing
   it is rather than every chip being the same rust eyebrow:

     .pill--rust   the section eyebrow — what this block is about
     .pill--brass  money, plans, anything with a number in it
     .pill--pine   neutral / structural labels
     .pill--ghost  quiet metadata ("Sample data")

   Everything shares one transition curve so the page feels like one object.
   =========================================================================== */

:root{ --ease-out:cubic-bezier(.22,.85,.3,1); --ease-pop:cubic-bezier(.34,1.4,.64,1); }

.pill{display:inline-flex; align-items:center; gap:7px;
  font-family:'IBM Plex Mono', monospace; font-size:11.5px; font-weight:600;
  letter-spacing:.1em; text-transform:uppercase;
  padding:5px 12px; border-radius:999px; border:1px solid transparent;
  transition:transform .2s var(--ease-pop), box-shadow .2s var(--ease-out),
             border-color .2s var(--ease-out), background .2s var(--ease-out);}
/* The leading dot. Small, and it does a surprising amount — it turns a word in
   a rounded rectangle into something that looks like a status. */
.pill::before{content:""; width:6px; height:6px; border-radius:50%; flex:none;
  background:currentColor; opacity:.85;}
.pill--nodot::before{display:none;}

.pill--rust{background:rgba(181,75,42,.10); border-color:rgba(181,75,42,.28); color:var(--rust);}
.pill--brass{background:rgba(184,134,43,.12); border-color:rgba(184,134,43,.32); color:#8A6417;}
.pill--pine{background:var(--pine-soft); border-color:rgba(30,61,47,.18); color:var(--head);}
.pill--ghost{background:transparent; border-color:var(--line); color:var(--grey);}

/* Interactive pills only. A static label shouldn't move under the cursor. */
a.pill:hover, button.pill:hover{transform:translateY(-1px);}
a.pill:active, button.pill:active{transform:translateY(0);}

html[data-theme="dark"] .pill--rust{
  background:linear-gradient(180deg, rgba(217,116,76,.20), rgba(217,116,76,.08));
  border-color:rgba(217,116,76,.36); color:#F0A183; box-shadow:var(--edge);}
html[data-theme="dark"] .pill--brass{
  background:linear-gradient(180deg, rgba(215,165,68,.20), rgba(215,165,68,.07));
  border-color:rgba(215,165,68,.36); color:#E8C077; box-shadow:var(--edge);}
html[data-theme="dark"] .pill--pine{
  background:linear-gradient(180deg, rgba(233,228,214,.09), rgba(233,228,214,.03));
  border-color:rgba(233,228,214,.18); color:#CBD6CE; box-shadow:var(--edge);}
html[data-theme="dark"] .pill--ghost{
  border-color:rgba(233,228,214,.16); color:#9AA79F;}

/* The legend becomes three pills whose dots ARE the chart's colors, so the
   key and the thing it keys share one visual language. */
.viz-legend span{padding:5px 12px 5px 10px; border-radius:999px;
  border:1px solid var(--line); background:rgba(30,61,47,.03);
  font-size:12.5px; transition:border-color .2s var(--ease-out),
  background .2s var(--ease-out), transform .2s var(--ease-pop);}
.viz-legend span:hover{transform:translateY(-1px); border-color:rgba(184,134,43,.45);}
html[data-theme="dark"] .viz-legend span{
  background:rgba(233,228,214,.045); border-color:rgba(233,228,214,.15);
  box-shadow:var(--edge);}

/* ---- micro-interactions --------------------------------------------------
   Nothing here is decorative motion for its own sake. Each one answers a
   question the pointer is asking: is this clickable, did my click register,
   where am I. */

/* Buttons: lift on hover, press down on click. The active state matters more
   than the hover one — it's the only feedback a touch user gets. */
.btn, .btn-primary, .btn-ghost, .cta-primary, .cta-secondary, .login-link,
.switch-tab, .theme-toggle{
  transition:transform .18s var(--ease-pop), box-shadow .2s var(--ease-out),
             background .2s var(--ease-out), border-color .2s var(--ease-out),
             color .2s var(--ease-out);}
.btn:hover, .btn-primary:hover, .btn-ghost:hover, .cta-primary:hover,
.cta-secondary:hover, .login-link:hover, .theme-toggle:hover{transform:translateY(-2px);}
.btn:active, .btn-primary:active, .btn-ghost:active, .cta-primary:active,
.cta-secondary:active, .login-link:active, .switch-tab:active,
.theme-toggle:active{transform:translateY(0); transition-duration:.06s;}

/* A light sweep across the primary CTA on hover. One pass, 600ms, and it only
   runs on a real pointer — on touch it would fire on every tap. */
@media (hover:hover){
  .btn-primary, .cta-primary{position:relative; overflow:hidden;}
  .btn-primary::after, .cta-primary::after{
    content:""; position:absolute; inset:0; pointer-events:none;
    background:linear-gradient(105deg, transparent 35%,
      rgba(255,255,255,.28) 50%, transparent 65%);
    transform:translateX(-120%); transition:transform .6s var(--ease-out);}
  .btn-primary:hover::after, .cta-primary:hover::after{transform:translateX(120%);}
}

/* Nav links grow an underline from the center rather than snapping one on. */
.nav-links > li > a{position:relative;}
.nav-links > li > a::after{content:""; position:absolute; left:0; right:0; bottom:-4px;
  height:2px; border-radius:2px; background:var(--rust);
  transform:scaleX(0); transition:transform .22s var(--ease-out);}
.nav-links > li > a:hover::after{transform:scaleX(1);}

/* Cards lift toward the reader. Photos get a slow inner zoom — slow enough to
   feel like the image breathing, not like a carousel. */
.photo-media{transition:transform .35s var(--ease-out), box-shadow .35s var(--ease-out);}
.photo-media img{transition:transform 1.1s var(--ease-out);}
.photo-media:hover{transform:translateY(-3px);}
.photo-media:hover img{transform:scale(1.035);}
.post-card{transition:transform .22s var(--ease-out), box-shadow .22s var(--ease-out),
  border-color .22s var(--ease-out);}
.post-card:hover{transform:translateY(-3px);}

/* The FAQ's +/– rotates instead of swapping glyphs. */
.faq summary::after{transition:transform .22s var(--ease-pop), color .2s var(--ease-out);}
.faq details[open] summary::after{transform:rotate(180deg);}

/* Stat-band numbers get their separator drawn in under them as they count. */
.statband .sep{transform:scaleX(0); transform-origin:left;
  transition:transform .7s var(--ease-out) .2s;}
[data-motion].in .statband .sep,
.statband.in .sep{transform:scaleX(1);}

/* The brass hairline on each dark band arrives rather than being there. */
html[data-theme="dark"] .feature-panel::after,
html[data-theme="dark"] .devices::after,
html[data-theme="dark"] .cta-banner::after,
html[data-theme="dark"] .faq-dark::after{
  transform:scaleX(.3); opacity:0; transform-origin:center;
  transition:transform .9s var(--ease-out) .15s, opacity .5s ease .15s;}
html[data-theme="dark"] [data-motion].in.feature-panel::after,
html[data-theme="dark"] [data-motion].in.devices::after,
html[data-theme="dark"] [data-motion].in.faq-dark::after,
html[data-theme="dark"] .cta-banner::after{transform:scaleX(1); opacity:1;}

/* (The toggle's dot was replaced by the sun/moon icons — see .tt-icons.) */

@media (prefers-reduced-motion: reduce){
  .btn, .btn-primary, .btn-ghost, .cta-primary, .cta-secondary, .login-link,
  .switch-tab, .theme-toggle, .pill, .viz-legend span, .photo-media,
  .photo-media img, .post-card, .mega-feature, .mega > *, .statband .sep,
  .faq summary::after, .nav-links > li > a::after{
    transition:none !important; transform:none !important;}
  .btn-primary::after, .cta-primary::after{display:none;}
  .mega > *{opacity:1;}
  .statband .sep{transform:scaleX(1) !important;}
  html[data-theme="dark"] .feature-panel::after,
  html[data-theme="dark"] .devices::after,
  html[data-theme="dark"] .cta-banner::after,
  html[data-theme="dark"] .faq-dark::after{
    transform:scaleX(1) !important; opacity:1; transition:none;}
}

/* ===========================================================================
   DARK THEME — LIGHT BANNERS
   Full-bleed cream bands cutting across the dark page. This is the strongest
   rhythm device available: after three or four dark blocks the eye stops
   registering the differences between them, and one light band resets it
   completely.

   Full-bleed is done with 100vw + a negative half-viewport offset rather than
   by restructuring the markup, so any <section> can become a banner by adding
   one class. Inside the band the palette flips back to the LIGHT theme values,
   which is what keeps the text legible — a light band inheriting dark-mode
   token values is exactly the dark-on-dark trap.
   =========================================================================== */

html[data-theme="dark"] .band-light{
  position:relative; isolation:isolate;
  padding-top:56px; padding-bottom:56px; margin-top:26px; margin-bottom:26px;
  /* light-theme values, restored locally */
  --cream:#F4EFE1; --paper-card:#fcfdfb; --pine-soft:#e3eee8;
  --ink:#24211B; --grey:#6B675C; --head:#1E3D2F;
  --rust:#B54B2A; --rust-soft:#f5e6e4;
  --brass:#b8862b; --brass-soft:#f5ebd6;
  --line:rgba(30,61,47,0.14);
  --lift-1:0 1px 2px rgba(30,61,47,.06), 0 4px 12px rgba(30,61,47,.05);
  --lift-2:0 2px 4px rgba(30,61,47,.07), 0 12px 28px rgba(30,61,47,.08);
  --lift-3:0 4px 8px rgba(30,61,47,.08), 0 28px 64px rgba(30,61,47,.13);
  --edge:none; --edge-strong:none;
  color:var(--ink);
}
/* The band itself: full viewport width regardless of the container it sits in.
   z-index:-1 keeps it behind the section's own content. */
html[data-theme="dark"] .band-light::before{
  content:""; position:absolute; z-index:-1; top:0; bottom:0;
  left:50%; margin-left:-50vw; width:100vw;
  background:
    linear-gradient(180deg, #F7F3E7 0%, var(--cream) 55%, #EFE9D8 100%);
  border-top:1px solid rgba(30,61,47,.10);
  border-bottom:1px solid rgba(30,61,47,.10);
  box-shadow:inset 0 12px 26px -18px rgba(0,0,0,.5),
             inset 0 -12px 26px -18px rgba(0,0,0,.5);}
/* The ledger rule returns inside the band — it's the light theme's texture,
   and without it the band is a flat slab next to a page that has grain. */
html[data-theme="dark"] .band-light::after{
  content:""; position:absolute; z-index:-1; inset:0;
  left:50%; margin-left:-50vw; width:100vw;
  background-image:linear-gradient(transparent 0, transparent 27px, rgba(30,61,47,.07) 28px);
  background-size:100% 28px; pointer-events:none;}

html[data-theme="dark"] .band-light h1,
html[data-theme="dark"] .band-light h2,
html[data-theme="dark"] .band-light h3{color:var(--head);}
html[data-theme="dark"] .band-light .viz,
html[data-theme="dark"] .band-light .switch-panels{
  background:var(--paper-card); border-color:var(--line);
  box-shadow:var(--lift-2);}
html[data-theme="dark"] .band-light .bar .kept{background:var(--pine);}
html[data-theme="dark"] .band-light .split-seg.keep{background:var(--pine); color:var(--on-dark);}
html[data-theme="dark"] .band-light .viz-legend .k{background:var(--pine);}
html[data-theme="dark"] .band-light .bar .val{background:var(--paper-card); border:0;}
html[data-theme="dark"] .band-light .salary-tag,
html[data-theme="dark"] .band-light .viz-note{background:var(--paper-card);}
html[data-theme="dark"] .band-light .viz-legend span{
  background:rgba(30,61,47,.03); border-color:var(--line); box-shadow:none;}
html[data-theme="dark"] .band-light .switch-tab{
  background:var(--paper-card); border-color:var(--line); color:var(--grey);
  box-shadow:none;}
html[data-theme="dark"] .band-light .switch-tab[aria-selected="true"]{
  background:var(--pine); border-color:var(--pine); color:var(--on-dark);
  box-shadow:0 3px 10px rgba(30,61,47,.22);}
html[data-theme="dark"] .band-light .photo-media img{filter:none;}
html[data-theme="dark"] .band-light .photo-media{box-shadow:var(--lift-2);}

/* Consecutive banners collapse into one continuous band instead of showing a
   seam of page color between them. */
html[data-theme="dark"] .band-light + .band-light{margin-top:-26px; padding-top:8px;}
html[data-theme="dark"] .band-light + .band-light::before{border-top:0;}

@media (max-width:640px){
  html[data-theme="dark"] .band-light{padding-top:38px; padding-bottom:38px;}
}

/* ===========================================================================
   DARK THEME — READABILITY
   Anywhere a light surface survived the token swap, its text has to survive
   with it. These are the places that would otherwise read dark-on-dark.
   =========================================================================== */

/* The product mockup is a PICTURE OF THE APP, and the app is light-themed.
   It should not follow the site's theme at all — a dark screenshot would be
   showing a product that doesn't exist. Pinned to explicit light values so it
   reads as a real screen sitting on a dark page. */
html[data-theme="dark"] .ui{
  --paper-card:#fcfdfb; --pine-soft:#e3eee8; --ink:#24211B; --grey:#6B675C;
  --head:#1E3D2F; --line:rgba(30,61,47,0.14);
  --rust-soft:#f5e6e4; --brass-soft:#f5ebd6;
  background:#fcfdfb; border-color:rgba(30,61,47,0.28);
  box-shadow:0 18px 44px rgba(0,0,0,.5);}
html[data-theme="dark"] .ui-bars i.lo{background:rgba(30,61,47,0.20);}
html[data-theme="dark"] .ui-note span,
html[data-theme="dark"] .collections{color:#24211B;}
html[data-theme="dark"] .ui-pill{border-color:rgba(30,61,47,0.16);}

/* Split-art tiles are light tint blocks holding a light UI card. Keep them
   light rather than half-converting them. */
html[data-theme="dark"] .split-art{border-color:rgba(233,228,214,.14);}
html[data-theme="dark"] .split-art.pine{background:#20392C;}
html[data-theme="dark"] .split-art.rust{background:#33211B;}
html[data-theme="dark"] .split-art.brass{background:#332918;}

/* Body copy sitting on the dark bands. #cfd9d2 was set for pine; on the new
   band tones it's fine, but these three were still inheriting --ink. */
html[data-theme="dark"] .statement .by{color:rgba(244,239,225,.66);}
html[data-theme="dark"] .statband span{color:#B9C4BC;}
html[data-theme="dark"] .photo-credit{color:#A8B5AC;}
html[data-theme="dark"] .feat-list li{color:#D3DBD5;}
html[data-theme="dark"] .lede{color:#D3DBD5;}
html[data-theme="dark"] .hero-micro,
html[data-theme="dark"] .dual-cta-note{color:#9AA79F;}
html[data-theme="dark"] .footer-col a,
html[data-theme="dark"] .footer-brand p{color:#A8B5AC;}
html[data-theme="dark"] .nav-links > li > a,
html[data-theme="dark"] .login-link{color:#D3DBD5;}
html[data-theme="dark"] .breadcrumb,
html[data-theme="dark"] .breadcrumb a{color:#9AA79F;}
html[data-theme="dark"] .breadcrumb [aria-current]{color:var(--head);}

/* ===========================================================================
   HERO DASHBOARD — AMBIENT MOTION
   The reveal animation (rings sweeping, numbers counting) fires once and then
   the panel is a still image for the rest of the visit. These are the loops
   that run after it: slow, low-amplitude, and none of them competing with the
   headline beside them for attention. A hero mock should look ALIVE, not
   busy — anything you notice twice is too much.

   All keyed off [data-motion].in so nothing starts before the reveal lands.
   =========================================================================== */

/* 1. The panel drifts. 9 seconds, 6px, plus a fraction of a degree of tilt —
      enough to read as floating rather than pasted on. */
@keyframes uiFloat{
  0%,100%{transform:translate3d(0,0,0) rotate(0deg);}
  50%    {transform:translate3d(0,-6px,0) rotate(-.22deg);}
}
[data-motion].in .laptop{animation:uiFloat 9s ease-in-out 1.6s infinite;}
@keyframes uiFloatB{
  0%,100%{transform:translate3d(0,0,0);}
  50%    {transform:translate3d(0,-9px,0);}
}
[data-motion].in .phone{animation:uiFloatB 7.5s ease-in-out 2.2s infinite;}

/* 2. A screen glare crossing the laptop every 11 seconds. This is the one that
      sells it as a physical device — a flat panel never catches light. */
.laptop .screen{position:relative; overflow:hidden;}
.laptop .screen::after{
  content:""; position:absolute; inset:-40% -10%; pointer-events:none; z-index:3;
  background:linear-gradient(102deg, transparent 42%,
    rgba(255,255,255,.20) 50%, transparent 58%);
  transform:translateX(-130%);}
[data-motion].in .laptop .screen::after{
  animation:uiGlare 11s cubic-bezier(.4,0,.2,1) 2.4s infinite;}
@keyframes uiGlare{
  0%     {transform:translateX(-130%);}
  16%,100%{transform:translateX(130%);}
}

/* 3. The health grade pulses once when it arrives, then a soft ring every few
      seconds — the app's own "this is your current standing" beat. */
@keyframes gradePulse{
  0%,88%,100%{box-shadow:0 0 0 0 rgba(31,102,80,0);}
  92%        {box-shadow:0 0 0 5px rgba(31,102,80,.16);}
}
.health-grade{padding:2px 9px; border-radius:999px; background:rgba(31,102,80,.10);}
[data-motion].in .health-grade{animation:gradePulse 6s ease-out 2.6s infinite;}

/* 4. A live dot on the title bar. Every dashboard worth the name is showing
      data that is still arriving; this says so in 8 pixels. */
.ui-bar{position:relative;}
.ui-bar::after{
  content:""; position:absolute; right:12px; top:50%; margin-top:-3px;
  width:6px; height:6px; border-radius:50%; background:#63C08F; opacity:0;}
[data-motion].in .ui-bar::after{animation:livePing 3.4s ease-in-out 2.8s infinite;}
@keyframes livePing{
  0%,100%{opacity:.35; box-shadow:0 0 0 0 rgba(99,192,143,.5);}
  50%    {opacity:1;   box-shadow:0 0 0 4px rgba(99,192,143,0);}
}

/* 5. The tallest income bar breathes, so the chart isn't frozen. One bar only:
      animating all of them reads as a loading state. */
@keyframes barBreathe{
  0%,100%{transform:scaleY(1);}
  50%    {transform:scaleY(1.06);}
}
[data-motion].in .ui-bars i:nth-child(7){
  transform-origin:bottom; animation:barBreathe 4.5s ease-in-out 3s infinite;}

/* 6. The dial rings hold a faint brass bloom that swells and fades, tying the
      three of them together as one instrument. */
@keyframes arcGlow{
  0%,100%{filter:drop-shadow(0 0 2px rgba(184,134,43,.18));}
  50%    {filter:drop-shadow(0 0 6px rgba(184,134,43,.38));}
}
[data-motion].in .dial-arc{animation:arcGlow 5.5s ease-in-out 2.2s infinite;}

/* Hover parks every loop. If someone is actually looking at the panel, the
   panel should hold still for them. */
.hero-art:hover .laptop,
.hero-art:hover .phone,
.hero-art:hover .dial-arc,
.hero-art:hover .ui-bars i,
.hero-art:hover .health-grade,
.hero-art:hover .laptop .screen::after,
.hero-art:hover .ui-bar::after{animation-play-state:paused;}

@media (prefers-reduced-motion: reduce){
  [data-motion].in .laptop, [data-motion].in .phone,
  [data-motion].in .laptop .screen::after, [data-motion].in .health-grade,
  [data-motion].in .ui-bar::after, [data-motion].in .ui-bars i:nth-child(7),
  [data-motion].in .dial-arc{animation:none !important;}
  .laptop .screen::after{display:none;}
  [data-motion].in .ui-bar::after{opacity:.5;}
}

/* ===========================================================================
   HERO STAGE — tilted phone with popout cards
   The composition from the reference: a dark panel, contour lines across it,
   a colored bloom behind a phone held at an angle, and white cards flying
   out of the screen toward the reader.

   The stage is dark in BOTH themes. In dark mode it belongs to the page; in
   light mode it becomes the one dark object above the fold, which is exactly
   how the reference uses it — the hero art is the anchor, not another pale
   rectangle in a pale page.
   =========================================================================== */

.hero-art{aspect-ratio:auto; background:none; border:0; padding:0; box-shadow:none;
  display:block; perspective:1400px;}

.hero-stage{position:relative; isolation:isolate; overflow:hidden;
  border-radius:22px; padding:38px 26px 30px;
  min-height:470px; display:flex; flex-direction:column;
  align-items:center; justify-content:center;
  background:radial-gradient(120% 100% at 70% 8%, #1B3628 0%, #10231A 45%, #08150F 100%);
  border:1px solid rgba(233,228,214,.10);
  box-shadow:0 30px 70px rgba(0,0,0,.42), inset 0 1px 0 rgba(233,228,214,.09);}

/* Contour lines. currentColor so one SVG serves both themes. */
.stage-waves{position:absolute; inset:0; width:100%; height:100%; z-index:0;
  color:rgba(150,214,183,.16); pointer-events:none;}

/* The bloom the phone sits in. Brass rather than the reference's cyan — this
   is the brand's light source everywhere else on the page. */
.stage-glow{position:absolute; z-index:0; pointer-events:none;
  left:50%; top:48%; width:min(430px,92%); aspect-ratio:1; transform:translate(-50%,-50%);
  background:radial-gradient(circle, rgba(184,134,43,.34) 0%, rgba(94,156,124,.16) 38%, transparent 68%);
  filter:blur(10px);}

.stage-devices{position:relative; z-index:2; width:100%;
  display:flex; align-items:center; justify-content:center;
  transform-style:preserve-3d;}

/* The phone, held at an angle. Two rotations plus a slight Y translation:
   a single rotate reads as a tilted rectangle, two read as an object in a
   room. The device frame itself is unchanged — this is a transform on top. */
.phone-3d{transform:rotateY(-17deg) rotateX(5deg) rotateZ(-3deg);
  transform-origin:60% 50%;
  filter:drop-shadow(-18px 26px 34px rgba(0,0,0,.55));}
.hero-stage .phone{width:min(220px, 46%); flex:none; margin:0;}

/* ---- the real dashboard screenshot -------------------------------------
   A browser window laid back on the stage. Three things make a screenshot
   read as a product rather than as a picture of a screen:

     1. Chrome. Without a title bar and a URL it is an image; with them it is
        a thing running somewhere.
     2. A single X rotation, not two. The phone above gets rotateY + rotateX
        because it is an object you hold. A browser window is a plane, and
        tilting it on two axes makes the text on it illegible fast — which
        defeats the entire point of using a real screenshot.
     3. A bottom fade. The capture is cut off, and a hard edge reads as a
        broken image. Faded, it reads as a page that continues.

   The dashboard is dark and so is the stage, so the frame gets a light
   border to separate them. */
.hero-shot{margin:0; width:min(900px, 100%); position:relative;
  border-radius:14px; overflow:hidden;
  background:#0E1A14; border:1px solid rgba(233,228,214,.16);
  box-shadow:0 40px 80px rgba(0,0,0,.55), 0 4px 12px rgba(0,0,0,.4),
             inset 0 1px 0 rgba(233,228,214,.10);}
.shot-3d{transform:perspective(2600px) rotateX(5deg);
  transform-origin:50% 100%;}

.shot-chrome{display:flex; align-items:center; gap:7px;
  padding:9px 13px; background:rgba(233,228,214,.055);
  border-bottom:1px solid rgba(233,228,214,.10);}
.shot-dot{width:9px; height:9px; border-radius:50%; flex:none;
  background:rgba(233,228,214,.22);}
.shot-url{margin-left:14px; font-family:'IBM Plex Mono', monospace;
  font-size:10.5px; letter-spacing:.04em; color:rgba(233,228,214,.42);}

/* The window. The image inside it is the WHOLE dashboard and is far taller
   than the frame, so it pans: rings first, then budgets, money flow, the
   six-month chart and the activity list. 58.1% is not a round number by
   accident -- it is (1 - windowAspect/imageAspect) for a 16:11 window and a
   1600x2624 image, i.e. exactly the overhang. Change the image and this
   number changes with it. */
.shot-window{position:relative; overflow:hidden; aspect-ratio:16/11;}
.shot-img{position:absolute; left:0; top:0; width:100%; height:auto; display:block;
  animation:shotPan 30s cubic-bezier(.5,0,.5,1) infinite alternate;}
@keyframes shotPan{from{transform:translateY(0);} to{transform:translateY(-58.1%);}}
/* The window's own bottom edge, softened so the cut looks intended. */
.shot-window::after{content:""; position:absolute; inset:auto 0 0 0; height:12%;
  background:linear-gradient(to bottom, transparent, rgba(8,21,15,.85));
  pointer-events:none;}

/* ===========================================================================
   DEVICE DUO — laptop + phone, replacing the browser-chrome frame.

   The old hero framed the dashboard in a fake browser window with three dots
   and a URL. It read as a screenshot of a website. A laptop and a phone
   together say the thing the band above the footer says in words: this runs on
   the desktop AND in your pocket.

   The screen image is the real app with the account data repainted, cropped to
   a true 16:10 (make-dashboard-hero.py).

   Built in 3D, not as a rectangle with a bar under it: the lid leans back and
   the deck lies away from the viewer, so the keyboard is foreshortened the way
   it is in a photograph. Colours are aluminium neutrals rather than the site's
   greens on purpose -- a laptop tinted to match the page reads as an
   illustration of a laptop.
   =========================================================================== */
.device-duo{position:relative; width:min(600px,100%); margin:0 auto;}

/* Perspective on the parent, rotations on the children, preserve-3d between:
   rotateX with no perspective anywhere in the chain is an orthographic squash,
   not a rotation. 2600 rather than 1900, and the vanishing point near the top
   of the lid -- at 1900 with the origin a third of the way down, the deck's
   near edge flared wider than the screen above it. */
.duo-laptop{position:relative; z-index:1;
  perspective:2600px; perspective-origin:50% 12%;}

/* ---- the lid ---------------------------------------------------------- */
/* Three layers, because that is what the object has: an aluminium shell, a
   black bezel, then glass. One gradient pretending to be all three is the
   difference between "laptop" and "screenshot with a border". */
.duo-lid{position:relative; transform-style:preserve-3d;
  transform:rotateX(-3deg); transform-origin:50% 100%;
  border-radius:15px 15px 4px 4px; padding:6px 6px 7px;
  background:
    linear-gradient(180deg,rgba(255,255,255,.55),rgba(255,255,255,0) 22%),
    linear-gradient(96deg,#E4E7E5 0%,#B9BFBC 6%,#9AA19D 16%,#8B928E 50%,
                    #A3AAA6 84%,#C9CFCC 95%,#EDEFEE 100%);
  box-shadow:0 30px 54px rgba(0,0,0,.5), 0 4px 12px rgba(0,0,0,.38),
             inset 0 0 0 1px rgba(255,255,255,.28);}
.duo-bezel{position:relative; border-radius:9px 9px 2px 2px;
  padding:9px 9px 14px; background:#0A0C0B;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);}
.duo-display{display:block; width:100%; height:auto; border-radius:2px;
  background:#0B100E;}
/* The camera, in the bezel where it belongs. Small, but its absence is one of
   the things that makes a CSS laptop look like a rectangle with a picture. */
.duo-bezel::before{content:""; position:absolute; z-index:2; top:3.5px; left:50%;
  width:4px; height:4px; margin-left:-2px; border-radius:50%;
  background:#202623; box-shadow:0 0 0 1px rgba(255,255,255,.06);}
/* The etched wordmark under the screen, and the glass sheen over it. */
.duo-bezel::after{content:""; position:absolute; inset:0; pointer-events:none;
  border-radius:inherit;
  background:linear-gradient(108deg,rgba(255,255,255,.10) 0%,
             rgba(255,255,255,.025) 24%,transparent 46%);}

/* ---- the deck --------------------------------------------------------- */
/* Depth 0.52 of the width, not the 0.706 of a real MacBook footprint: the
   honest number made the deck taller on screen than a third of the lid and the
   laptop became a table.

   margin-bottom claws back what the transform does not: a transform paints
   somewhere else but still occupies its ORIGINAL box, so the deck reserved its
   full untransformed depth in layout while drawing a fraction of it -- about
   170px of dead stage under the laptop. Measured, not derived from cos(73deg),
   because perspective lengthens the near edge. */
.duo-deck{position:relative; margin:0 -1.2% -28.5%;
  aspect-ratio:1 / .52;
  transform:rotateX(73deg); transform-origin:50% 0;
  border-radius:3px 3px 20px 20px;
  background:
    linear-gradient(180deg,#9DA4A0 0%,#D3D8D5 3%,#E7EAE8 14%,#DCE0DE 62%,
                    #C2C8C5 88%,#A6ADA9 97%,#8D9490 100%),
    linear-gradient(90deg,#A8AFAB 0%,#E9ECEA 8%,#E9ECEA 92%,#A8AFAB 100%);
  background-blend-mode:multiply;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5);}
/* The hinge shadow where the deck meets the lid. */
.duo-deck::before{content:""; position:absolute; left:1.5%; right:1.5%; top:0;
  height:4%; border-radius:0 0 6px 6px;
  background:linear-gradient(180deg,rgba(0,0,0,.5),rgba(0,0,0,0));}
/* The finger recess on the front edge. */
.duo-deck::after{content:""; position:absolute; left:43%; width:14%; bottom:0;
  height:4.5%; border-radius:10px 10px 0 0;
  background:linear-gradient(180deg,rgba(0,0,0,.22),rgba(0,0,0,.10));}

/* The keyboard well: keys sit recessed, not painted on. */
.duo-well{position:absolute; left:7.5%; right:7.5%; top:9%; height:42%;
  display:flex; flex-direction:column; gap:1.6%;
  padding:1.4% 1.2%; border-radius:4px; background:#171A19;
  box-shadow:inset 0 2px 5px rgba(0,0,0,.6), 0 1px 0 rgba(255,255,255,.5);}
/* Each row is one gradient: dark key tops, gaps the colour of the well. The
   key COUNT differs per row, which is where the shape comes from. */
.kr{display:block; flex:1 1 auto; border-radius:1.5px;
  background-color:#333835;}
.kr1{flex:0 0 11%;}                    /* function row, short */
.kr1{background-image:repeating-linear-gradient(90deg,transparent 0 calc(100%/14 - 2px),#171A19 calc(100%/14 - 2px) calc(100%/14));}
.kr2{background-image:repeating-linear-gradient(90deg,transparent 0 calc(100%/14 - 2px),#171A19 calc(100%/14 - 2px) calc(100%/14));}
.kr3{background-image:repeating-linear-gradient(90deg,transparent 0 calc(100%/14 - 2px),#171A19 calc(100%/14 - 2px) calc(100%/14));}
.kr4{background-image:repeating-linear-gradient(90deg,transparent 0 calc(100%/13 - 2px),#171A19 calc(100%/13 - 2px) calc(100%/13));}
.kr5{background-image:repeating-linear-gradient(90deg,transparent 0 calc(100%/12 - 2px),#171A19 calc(100%/12 - 2px) calc(100%/12));}
/* The bottom row is mostly spacebar: four modifiers, the bar, four more. */
.kr6{background-image:linear-gradient(90deg,
  #333835 0 7%, #171A19 7% 7.9%, #333835 7.9% 15%, #171A19 15% 15.9%,
  #333835 15.9% 23%, #171A19 23% 23.9%, #333835 23.9% 31%, #171A19 31% 31.9%,
  #333835 31.9% 68%, #171A19 68% 68.9%, #333835 68.9% 76%, #171A19 76% 76.9%,
  #333835 76.9% 84%, #171A19 84% 84.9%, #333835 84.9% 100%);}

.duo-trackpad{position:absolute; left:34%; width:32%; top:57%; height:29%;
  border-radius:4px;
  background:linear-gradient(180deg,#CED4D1,#DDE1DF 40%,#D2D8D5);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.14), inset 0 1px 2px rgba(0,0,0,.10);}

/* Contact shadow on the surface. The deck is transformed, so it casts nothing
   useful of its own -- without this the laptop floats. */
.duo-shadow{position:absolute; z-index:-1; left:6%; right:6%;
  bottom:-3%; height:44px; border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%,
             rgba(0,0,0,.55) 0%, rgba(0,0,0,.28) 45%, transparent 72%);
  filter:blur(7px);}

/* ---- the phone -------------------------------------------------------- */
/* Anchored by its TOP, not its bottom, and with no min-width. Both matter.

   The phone has to clear the dials -- they are the argument of the image, and
   the tax-cover one reading 100% is the best of them. Anchoring the bottom made
   that clearance depend on the phone's own height, which scales with its width,
   so the same rule that looked right at 1440 put the phone across the dials at
   390. A min-width made it worse: below about 700px the phone stopped shrinking
   with the laptop and simply swamped it.

   top:56% pins the gap to the LID, so the dials are clear at every width by
   construction rather than by tuning. */
/* 24% of the duo, not 15%. In the reference the phone is about a quarter of the
   laptop's width and its base finishes level with the deck -- at 15% it read as
   an accessory rather than the second device the image is about.

   The size is not free-floating: 24% x 2.174 (the screenshot's aspect) is 52%
   of the duo's width in height, so the top position and the width are one
   decision, not two. top:44% is measured to land two things at once -- the
   phone's head below the dials (they end at 52% of the LID; it starts at 60%)
   and its foot level with the deck's. Change the width and both have to be
   recomputed.

   Note the percentage is of the DUO, which includes the deck's box, not of the
   lid -- 44% here is 60% of the lid. Reading it as a lid percentage is how the
   phone ended up over the dials once already. */
.duo-phone{position:absolute; z-index:3; right:-5%; top:44%;
  width:24%; margin:0;}
/* Neutral near-black with a blue cast, like the reference, rather than the
   greenish frame it had. A phone tinted to the site's palette reads as a
   drawing of a phone. */
.duo-frame{position:relative; border-radius:14.5%/6.8%; padding:2.9%;
  background:linear-gradient(104deg,#2E343B 0%,#14181D 22%,#0C0F13 60%,#272C33 100%);
  box-shadow:0 0 0 1px rgba(233,228,214,.14),
             -16px 28px 48px rgba(0,0,0,.62), -4px 8px 16px rgba(0,0,0,.45);}
.duo-frame::after{content:""; position:absolute; inset:0; border-radius:inherit;
  pointer-events:none;
  background:linear-gradient(104deg,rgba(255,255,255,.34) 0 .6%,transparent 2.2%,
             transparent 97.6%,rgba(255,255,255,.26) 99.2% 100%);}
.duo-screen{display:block; width:100%; height:auto; border-radius:12%/5.4%;}
.duo-island{position:absolute; z-index:2; left:50%; top:3.4%;
  transform:translateX(-50%); width:30%; height:2.2%;
  border-radius:999px; background:#040605;}

@media (max-width:760px){
  .duo-phone{width:27%; right:-3%;}
  .duo-lid{padding:4px 4px 5px;}
  .duo-bezel{padding:6px 6px 9px;}
}
@media (prefers-reduced-motion:reduce){
  .duo-lid{transform:none;}
}

/* The stage clips its overflow, and the phone deliberately hangs below the
   laptop's deck -- so the stage needs the room, or the bottom of the phone is
   simply cut off. Extra bottom padding rather than overflow:visible, because
   the clip is what stops the popouts escaping the panel. */
/* Was 132px, sized for a phone that hung far below the old flat base. The
   laptop now has a deck, so the duo is taller and that padding pushed the top
   of the lid out through the stage's clip. */
/* On the shot variant the cards overhang the window's edges, which is what
   makes them read as coming off it rather than sitting on it. */
.hero-stage--shot .stage-devices{perspective:1800px;}
/* TWO BUGS LIVED HERE. Both were invisible until the page was actually
   rendered, which is the lesson.

   1. .pop-3's base rule sets `bottom:9%` for the old three-card layout. This
      block then added `top:47%`. An absolutely positioned box with BOTH top
      and bottom set stretches to fill the gap between them, so "Tax set aside"
      became a 230px-tall white slab. The horizontal equivalent was masked on
      the other cards by width:max-content, which is why only this one showed.
      Fix: reset `inset` before positioning, so a stale edge from another rule
      can never combine with a new one.

   2. They were all different widths, because width:max-content sizes each card
      to its own longest line. Five different-sized cards read as five bugs.
      Fixed width now, and the second line ellipsizes into it.

   Positioned with top + one horizontal edge only. Never a pair on the same
   axis. */
.hero-art-wrap .hero-stage--shot .popout{
  inset:auto; width:262px; max-width:none;}
/* Laid out around the DEVICES, not over them. The previous set was spaced down
   both edges for a plain 16:11 window; against the laptop it put a card across
   the greeting, one across the dials and one across the profit row, so the
   thing the cards are pointing at was the thing they covered.

   The rings occupy roughly 34-62% of the lid's height, and the phone owns the
   right side below 55%. So: nothing between 30% and 62% on the left, nothing
   below 34% on the right. */
/* Measured off the rendered stage, not chosen by eye. In stage percentages:
   the dials occupy 29.2-38.9%, their captions run to 42.2%, and the phone's
   top-left corner is at 43.6% down / 68% across.

   So "below the ring" means top >= 43%, and clearing the phone means the card's
   RIGHT edge must land at or before 68% -- the cards are 25.4% of the stage
   wide, which puts the largest usable right offset at 33%. Bank connected sits
   in exactly that slot. */
.hero-art-wrap .hero-stage--shot .pop-1{top:5%;  right:6%;}
.hero-art-wrap .hero-stage--shot .pop-2{top:45%; right:33%;}
.hero-art-wrap .hero-stage--shot .pop-3{top:22%; left:6%;}
.hero-art-wrap .hero-stage--shot .pop-4{top:62%; left:8%;}
.hero-art-wrap .hero-stage--shot .pop-5{top:79%; left:13%;}
[data-motion].in .pop-4{transition-delay:1.15s; animation:popDrift 7.8s ease-in-out 2.9s infinite;}
[data-motion].in .pop-5{transition-delay:1.35s; animation:popDrift 6.9s ease-in-out 3.3s infinite;}
@media (max-width:900px){
  .hero-art-wrap .hero-stage--shot .pop-1,
  .hero-art-wrap .hero-stage--shot .pop-3,
  .hero-art-wrap .hero-stage--shot .pop-5{left:1%;}
  .hero-art-wrap .hero-stage--shot .pop-2,
  .hero-art-wrap .hero-stage--shot .pop-4{right:1%;}
  /* The desktop tops are 4/12/24%, which works only because the cards are
     262px in a 1032px stage and sit on opposite edges. Once they go full width
     here they are on the SAME column, so those three tops put card 2 across
     card 1. Re-spaced for a single column. */
  .hero-art-wrap .hero-stage--shot .pop-1{top:3%;}
  .hero-art-wrap .hero-stage--shot .pop-2{top:21%;}
  .hero-art-wrap .hero-stage--shot .pop-3{top:39%;}
}
@media (max-width:820px){
  /* Five cards will not fit a phone-width stage without stacking on each
     other. Three is the most that reads; the other two stand down. */
  .hero-art-wrap .hero-stage--shot .pop-3,
  .hero-art-wrap .hero-stage--shot .pop-4,
  .hero-art-wrap .hero-stage--shot .pop-5{display:none;}
}
@media (max-width:620px){
  /* And two do not fit either. The stage is 430px tall at this width and the
     cards are 43px on a single column, so the pair collided however they were
     spaced -- measured, not guessed. One card, no overlap, and the laptop
     underneath is small enough that it needs the room more than the second
     card does. */
  .hero-art-wrap .hero-stage--shot .pop-2{display:none;}
}
@media (max-width:820px){
  /* Below this the window is too narrow for its own text to survive a tilt. */
  .shot-3d{transform:none;}
  .shot-url{display:none;}
}

/* ---- popout cards -------------------------------------------------------
   White in both themes. They are the light in the picture — cards leaving a
   dark screen — and tinting them to the page would throw that away. */
.popout{position:absolute; z-index:3; display:flex; align-items:center; gap:10px;
  background:#FFFFFF; color:#1B2A22;
  border-radius:12px; padding:9px 11px;
  width:max-content; max-width:280px;
  box-shadow:0 16px 34px rgba(0,0,0,.34), 0 2px 6px rgba(0,0,0,.2);
  font-family:'IBM Plex Sans', system-ui, sans-serif;
  transform:translateY(14px) scale(.94); opacity:0;
  transition:opacity .5s var(--ease-out), transform .7s var(--ease-pop);}
.po-icon{flex:none; width:26px; height:26px; border-radius:8px;
  display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:700; line-height:1;}
.po-icon.in{background:#DFF0E6; color:#1F6650;}
.po-icon.tax{background:#F7EBD3; color:#8A6417;}
.po-icon.rec{background:#F6E3DD; color:#B54B2A; font-size:9px;}
.po-icon.bank{background:#E2E8F3; color:#33507E; letter-spacing:1px;}
.po-icon.mile{background:#E4EFE9; color:#2F6B54;}
.po-body{min-width:0;}
.po-body b{display:block; font-size:12.5px; font-weight:600; line-height:1.25;
  color:#16241D; white-space:nowrap;}
.po-body span{display:block; font-size:10.5px; line-height:1.3; color:#6B7A72;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.po-meta{margin-left:auto; text-align:right; flex:none;}
.po-chip{display:block; font-family:'IBM Plex Mono', monospace; font-size:11px;
  font-weight:600; color:#1B2A22;}
.po-chip.ok{color:#1F6650;}
.po-chip.tax{color:#8A6417;}
.po-meta em{display:block; font-style:normal; font-size:9px; letter-spacing:.06em;
  text-transform:uppercase; color:#9AA79F; margin-top:1px;}

/* Placement. Staggered left/right of the phone so they read as coming OUT of
   the screen rather than sitting in a column beside it. */
.pop-1{top:12%;  right:-2%;}
.pop-2{top:44%;  left:-6%;}
.pop-3{bottom:9%; right:4%;}

/* Arrival, then a slow drift. Each card has its own period so they never
   sync up into a single pulsing block. */
[data-motion].in .popout{opacity:1; transform:translateY(0) scale(1);}
[data-motion].in .pop-1{transition-delay:.55s;}
[data-motion].in .pop-2{transition-delay:.75s;}
[data-motion].in .pop-3{transition-delay:.95s;}
@keyframes popDrift{0%,100%{transform:translate3d(0,0,0);} 50%{transform:translate3d(0,-7px,0);}}
[data-motion].in .pop-1{animation:popDrift 6.5s ease-in-out 1.6s infinite;}
[data-motion].in .pop-2{animation:popDrift 8s   ease-in-out 2.1s infinite;}
[data-motion].in .pop-3{animation:popDrift 7.2s ease-in-out 2.6s infinite;}

/* ---- scroll cue ---------------------------------------------------------- */
.stage-cue{position:relative; z-index:3; margin:22px 0 0; display:flex;
  align-items:center; gap:9px;
  font-family:'IBM Plex Mono', monospace; font-size:10.5px; letter-spacing:.12em;
  text-transform:uppercase; color:rgba(233,228,214,.5);}
.cue-mouse{width:13px; height:20px; border-radius:7px; flex:none;
  border:1.3px solid rgba(233,228,214,.42); position:relative;}
.cue-mouse::after{content:""; position:absolute; left:50%; top:4px; margin-left:-1px;
  width:2px; height:4px; border-radius:1px; background:rgba(233,228,214,.7);
  animation:cueScroll 2s ease-in-out infinite;}
@keyframes cueScroll{0%,100%{transform:translateY(0); opacity:1;}
  60%{transform:translateY(6px); opacity:0;}}

/* The stage is dark, so the mock phone screen inside it keeps light values —
   same reasoning as .ui: it's a picture of a light-themed app. */
.hero-stage .phone .pscreen{background:#fcfdfb;}

@media (max-width:1000px){
  .pop-1{right:-8%;} .pop-2{left:-10%;}
  .popout{max-width:200px; padding:8px 10px;}
  .po-body b{font-size:11.5px;} .po-body span{font-size:10px;}
}
/* Below the grid break the popouts have nowhere to go — they'd overhang the
   viewport and force a horizontal scrollbar. Two of them tuck in, the third
   stands down. Losing one card costs nothing; a sideways-scrolling hero costs
   the whole first impression. */
@media (max-width:820px){
  .hero-stage{min-height:420px; padding:30px 18px 24px;}
  .hero-stage .phone{width:min(200px, 52%);}
  .pop-1{top:8%; right:0;}
  .pop-2{top:auto; bottom:14%; left:0;}
  .pop-3{display:none;}
}
@media (max-width:520px){
  .popout{max-width:172px;}
  .po-meta em{display:none;}
  .phone-3d{transform:rotateY(-11deg) rotateZ(-2deg);}
}

@media (prefers-reduced-motion: reduce){
  .shot-img{animation:none;}
  [data-motion].in .pop-4, [data-motion].in .pop-5,
  [data-motion].in .pop-1, [data-motion].in .pop-2, [data-motion].in .pop-3{
    animation:none !important; transition:none !important;
    opacity:1; transform:none;}
  .cue-mouse::after{animation:none;}
}

/* ===========================================================================
   LEOLIFT-STYLE LAYOUT
   Three format moves taken from the reference:
     1. the hero is CENTERED and stacked, with the product art full width below
     2. one call to action, shaped as a pill with a chevron
     3. every section opens the same way — small label, headline, one short
        paragraph, all centered — so the page has a repeating grammar instead of
        a different arrangement per section
   =========================================================================== */

/* ---- 1. centered hero ----------------------------------------------------- */
.hero{padding:76px 0 20px; text-align:center;}
.hero-lead{max-width:820px; display:flex; flex-direction:column; align-items:center;}
.hero-lead h1{font-size:clamp(38px, 6vw, 68px); line-height:1.02;
  letter-spacing:-.025em; margin:6px 0 20px; max-width:16ch;}
.hero-lead .lede{max-width:60ch; margin:0 0 30px; font-size:17.5px;}
.hero-lead .hero-actions{justify-content:center; margin:0;}
.hero-lead .hero-micro{margin-top:18px; max-width:52ch;}
.hero-art-wrap{margin-top:46px;}
/* The stage now has the full column, so it can be wider and shorter than it
   was in the old right-hand slot. */
.hero-art-wrap .hero-stage{min-height:520px; padding:44px 32px 34px;}
/* Air above the lid and room under the deck for the contact shadow.
   This has to be TWO classes and it has to sit after the rule above: the same
   declaration written as `.hero-stage--shot{...}` earlier in the file lost to
   `.hero-art-wrap .hero-stage` on both specificity and order, and quietly did
   nothing -- computed padding-top stayed 44px. */
.hero-art-wrap .hero-stage--shot{padding-top:78px; padding-bottom:64px;}
.hero-art-wrap .hero-stage .phone{width:min(240px, 34%);}
.hero-art-wrap .pop-1{top:16%;  right:12%;}
.hero-art-wrap .pop-2{top:46%;  left:10%;}
.hero-art-wrap .pop-3{bottom:16%; right:16%;}
@media (max-width:900px){
  .hero-art-wrap .pop-1{right:2%;} .hero-art-wrap .pop-2{left:0;}
  .hero-art-wrap .pop-3{right:4%;}
}
@media (max-width:820px){
  .hero{padding-top:48px;}
  .hero-art-wrap{margin-top:32px;}
  .hero-art-wrap .hero-stage{min-height:430px;}
  .hero-art-wrap .hero-stage .phone{width:min(200px, 52%);}
}

/* ---- mobile app band, above the footer -----------------------------------
   The last thing before the footer, so it has to be quiet. Centered, one
   rule above it, and nothing clickable — it is an announcement, not a CTA
   competing with the one directly above it. */
.app-band{text-align:center; padding:56px 0 44px; margin-top:8px;
  border-top:1px solid var(--line);
  display:flex; flex-direction:column; align-items:center;}
/* 23% is not a guess -- it is the same radius .mark uses in the nav and the
   footer, so the three instances of the logo on this page are now the same
   shape. brand-mark.png is opaque RGB with square corners, so the rounding has
   to come from CSS; it was missing here, which is why this one read as a hard
   square next to two squircles.

   Full opacity too. It was at .92 to sit quietly, but a dimmed logo beside two
   undimmed ones reads as a rendering fault rather than as restraint. */
.app-band-mark{width:52px; height:52px; margin-bottom:16px; border-radius:23%;}
.app-band-line{margin:0; font-family:var(--serif);
  font-size:clamp(21px, 2.6vw, 27px); line-height:1.2; letter-spacing:-.01em;
  color:var(--head);}
.app-band-sub{margin:10px auto 0; max-width:56ch; font-size:15px;
  line-height:1.6; color:var(--grey);}
@media (max-width:640px){
  .app-band{padding:42px 0 34px;}
  .app-band-mark{width:44px; height:44px;}
}

/* ---- 2. the pill CTA ----------------------------------------------------- */
.btn-arrow{border-radius:999px; display:inline-flex; align-items:center; gap:9px;}
.btn-arrow::before{content:""; order:2; width:6px; height:6px; flex:none;
  border-right:2px solid currentColor; border-top:2px solid currentColor;
  transform:rotate(45deg) translateX(-1px);
  transition:transform .2s var(--ease-out);}
.btn-arrow:hover::before{transform:rotate(45deg) translate(1px,-1px);}
/* White pill on the dark page — the reference's single highest-contrast
   object, and the only pure white on the page besides the popout cards. */
html[data-theme="dark"] .btn-arrow.btn-primary{
  background:#FBFAF6; color:#12211A; border-color:#FBFAF6;
  box-shadow:0 6px 22px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.9);}
html[data-theme="dark"] .btn-arrow.btn-primary:hover{background:#fff; border-color:#fff;}
html[data-theme="dark"] .btn-arrow.btn-primary::after{display:none;}

/* Also make the nav CTA a pill, so the two agree. */
/* NAV CTA ONLY — smaller than a body CTA, on purpose.
   .btn is sized for in-page calls to action (15px type, 13px/24px padding).
   Inherited straight into the header it produced a ~52px lozenge in bright
   brass, sitting beside 12.5px uppercase nav links — several times their
   optical weight, and shouting on every page before the reader has been told
   anything. The header's job is to stay available, not to compete with the
   headline underneath it. Back to the proportions the site used before:
   14px type, 10px/20px padding. Body CTAs are untouched and still full size. */
.nav-cta .btn{border-radius:999px; font-size:14px; padding:10px 20px;}
html[data-theme="dark"] .nav-cta .btn-primary{
  /* Flat fill rather than the gradient-plus-inner-highlight the big buttons
     carry. At this size the highlight is a bright line across the top edge,
     which is most of what read as glare. */
  background:var(--brass); box-shadow:none;}
html[data-theme="dark"] .nav-cta .btn-primary:hover{background:#E7B558;}

/* ---- 3. the section header pattern --------------------------------------
   Label, headline, one paragraph, centered. Applied by wrapping a section's
   opening copy in .sec-head — sections that already lead with a left-aligned
   h2 are untouched. */
.sec-head{text-align:center; max-width:640px; margin:0 auto 34px;
  display:flex; flex-direction:column; align-items:center;}
.sec-head .tag{margin-bottom:14px;}
.sec-head h2{margin:0 0 12px; letter-spacing:-.02em; max-width:18ch;}
.sec-head p{margin:0; color:var(--grey); font-size:16px; line-height:1.6;
  max-width:54ch;}
html[data-theme="dark"] .sec-head p{color:#9AA79F;}
html[data-theme="dark"] .band-light .sec-head p{color:var(--grey);}
@media (max-width:640px){ .sec-head{margin-bottom:26px;} }

/* Deeper page. The reference is nearly black; ours keeps a pine cast so it
   still reads as this brand, but it drops two steps so the raised surfaces
   have somewhere to sit above it. */
html[data-theme="dark"]{ --cream:#0A1710; --s1:#0A1710; }

/* ===========================================================================
   PRICING PANEL — Leolift structure
   One panel, hairline-divided columns. The reference's key move is that the
   tiers are NOT separate cards: separate cards ask "which product?", a divided
   panel asks "how far along this scale?", and the second question is the one a
   two-tier product wants asked.
   =========================================================================== */

.price-panel{display:grid; grid-template-columns:repeat(3, 1fr);
  border:1.5px solid var(--line); border-radius:18px; overflow:hidden;
  background:var(--paper-card); box-shadow:var(--lift-2); margin:8px 0 14px;}
.price-col{padding:34px 30px 32px; display:flex; flex-direction:column;
  border-left:1px solid var(--line); position:relative;}
.price-col:first-child{border-left:0;}

/* The featured column is marked by TONE, not by a border or a scale
   transform. Growing one column breaks the shared baseline that makes the
   prices comparable at a glance, which is the whole point of the panel. */
.price-col.is-featured{background:linear-gradient(180deg, rgba(184,134,43,.07), transparent 55%);}
.pc-flag{position:absolute; top:14px; right:16px;
  font-family:'IBM Plex Mono', monospace; font-size:9.5px; font-weight:600;
  letter-spacing:.11em; text-transform:uppercase; color:#8A6417;
  /* #8A6417 not var(--brass): brass on this 10%-brass pill is 2.87:1 in the
     light theme, under the 4.5 AA floor. The darker brass is 4.75:1 and is
     what .pill--brass already uses for the same tinted-pill pattern. The
     dark-theme override below sets its own color and is unaffected. */
  border:1px solid rgba(184,134,43,.34); border-radius:999px; padding:3px 9px;
  background:rgba(184,134,43,.10);}

.pc-name{font-family:'Fraunces', serif; font-size:21px; color:var(--head);
  margin:0 0 7px;}
.pc-blurb{font-size:14px; line-height:1.5; color:var(--grey); margin:0 0 22px;
  min-height:42px;}
.pc-from{font-family:'IBM Plex Mono', monospace; font-size:10.5px;
  letter-spacing:.11em; text-transform:uppercase; color:var(--grey);
  margin:0 0 4px;}
.pc-price{font-family:'Fraunces', serif; font-weight:600; font-size:46px;
  line-height:1; letter-spacing:-.025em; color:var(--head); margin:0 0 8px;}
.pc-price-sm{font-size:32px;}
.pc-terms{font-size:12.5px; line-height:1.5; color:var(--grey); margin:0 0 22px;
  min-height:38px;}
.pc-cta{width:100%; text-align:center; justify-content:center; margin-bottom:26px;}
.pc-feat-label{font-family:'IBM Plex Mono', monospace; font-size:10px;
  letter-spacing:.11em; text-transform:uppercase; color:var(--grey);
  margin:0 0 12px; padding-top:20px; border-top:1px solid var(--line);}
.price-panel .price-list{margin:0; padding:0; list-style:none;}
.price-panel .price-list li{position:relative; padding:0 0 10px 22px;
  font-size:14px; line-height:1.5; color:var(--ink);}
.price-panel .price-list li::before{content:""; position:absolute; left:0; top:7px;
  width:11px; height:6px; border-left:2px solid var(--brass);
  border-bottom:2px solid var(--brass); transform:rotate(-45deg);}
.price-panel .price-list.quiet li::before{
  border-color:var(--grey); width:8px; height:0; border-left:0; top:10px;
  transform:none;}

/* The trial column. Marked as the entry point with a cool tint and a brass
   top rule — different in kind from the featured column's warm wash, so the
   panel reads as "start here" then "recommended", not as two competing
   highlights. */
.price-col.is-entry{background:rgba(30,61,47,.028);}
.price-col.is-entry::before{content:""; position:absolute; top:0; left:0; right:0;
  height:3px; background:linear-gradient(90deg, var(--brass), rgba(184,134,43,0));}
.pc-note{margin:16px 0 0; padding-top:14px; border-top:1px solid var(--line);
  font-size:12px; line-height:1.5; color:var(--grey);}
/* $0 is the argument. Let it be the biggest thing in the column. */
.price-col.is-entry .pc-price{color:var(--head);}
.price-foot{font-size:12.5px; color:var(--grey); margin:0 0 8px; text-align:center;}

@media (max-width:900px){
  .price-panel{grid-template-columns:1fr;}
  .price-col{border-left:0; border-top:1px solid var(--line);}
  .price-col:first-child{border-top:0;}
  .pc-blurb, .pc-terms{min-height:0;}
}

/* ---- dark ---------------------------------------------------------------- */
html[data-theme="dark"] .price-panel{
  background:linear-gradient(180deg, #1A2E23 0%, var(--s2) 60%);
  border-color:rgba(233,228,214,.13);
  box-shadow:var(--edge), 0 18px 44px rgba(0,0,0,.4);}
html[data-theme="dark"] .price-col{border-left-color:rgba(233,228,214,.11);}
html[data-theme="dark"] .price-col.is-featured{
  background:linear-gradient(180deg, rgba(215,165,68,.11), transparent 55%);}
html[data-theme="dark"] .price-col.is-entry{background:rgba(233,228,214,.035);}
html[data-theme="dark"] .pc-note{border-top-color:rgba(233,228,214,.11); color:#9AA79F;}
html[data-theme="dark"] .pc-feat-label{border-top-color:rgba(233,228,214,.11);}
html[data-theme="dark"] .price-panel .price-list li{color:#D3DBD5;}
html[data-theme="dark"] .pc-flag{color:#E8C077; border-color:rgba(215,165,68,.4);
  background:rgba(215,165,68,.12);}
/* Only the featured column gets the white pill. Three white buttons in a row
   would leave the reader with no idea which one to press — which is the same
   as having no recommendation at all. */
html[data-theme="dark"] .price-col:not(.is-featured) .btn-primary.btn-arrow{
  background:linear-gradient(180deg, rgba(233,228,214,.09), rgba(233,228,214,.03));
  color:var(--head); border-color:rgba(233,228,214,.22); box-shadow:var(--edge);}
html[data-theme="dark"] .price-col:not(.is-featured) .btn-primary.btn-arrow:hover{
  background:rgba(233,228,214,.13); border-color:rgba(233,228,214,.34);}

/* Reveal the columns in sequence rather than as one block. */
.price-col{opacity:0; transform:translateY(14px);
  transition:opacity .5s var(--ease-out), transform .55s var(--ease-out);}
[data-motion].in .price-col{opacity:1; transform:none;}
[data-motion].in .price-col:nth-child(1){transition-delay:.05s;}
[data-motion].in .price-col:nth-child(2){transition-delay:.15s;}
[data-motion].in .price-col:nth-child(3){transition-delay:.25s;}

/* Centered pricing page header, matching the hero. */
.pricing-hero{max-width:720px; margin:0 auto; padding:56px 0 34px;
  display:flex; flex-direction:column; align-items:center; text-align:center;}
.pricing-hero h1{font-size:clamp(34px, 5vw, 56px); line-height:1.05;
  letter-spacing:-.025em; margin:4px 0 18px;}
.pricing-hero .lede{margin:0; max-width:56ch;}

@media (prefers-reduced-motion: reduce){
  .price-col{opacity:1; transform:none; transition:none;}
}

/* ===========================================================================
   PHOTO QUOTE / SCENARIO CARD
   Styled as a testimonial because it does a testimonial's visual job, but it
   carries a visible "Illustration" flag and attributes itself to nobody. The
   .is-real variant drops the flag and takes a name — see the note in
   index.html for when that becomes legitimate.
   =========================================================================== */

.photo-quote{margin:14px 0 0; padding:16px 18px 15px;
  background:var(--paper-card); border:1px solid var(--line);
  border-left:3px solid var(--rust); border-radius:12px;
  box-shadow:var(--lift-1); position:relative;}
.scenario-flag{position:absolute; top:-9px; right:14px;
  font-family:'IBM Plex Mono', monospace; font-size:9px; font-weight:600;
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--grey); background:var(--paper-card);
  border:1px solid var(--line); border-radius:999px; padding:2px 9px;}
.photo-quote blockquote{margin:0 0 11px; font-size:14.5px; line-height:1.55;
  color:var(--ink);}
.photo-quote blockquote em{font-style:normal; font-weight:600; color:var(--head);}
.photo-quote figcaption{display:flex; flex-direction:column; gap:1px;}
.photo-quote figcaption b{font-size:13px; font-weight:600; color:var(--head);}
.photo-quote figcaption span{font-size:11.5px; color:var(--grey);}

/* The honest version, for when there is a real person behind it. Quote marks
   and a name appear together or not at all. */
.photo-quote.is-real blockquote{font-family:'Fraunces', serif; font-size:16px;
  line-height:1.5; color:var(--head);}
.photo-quote.is-real{border-left-color:var(--brass);}

html[data-theme="dark"] .photo-quote{
  background:linear-gradient(180deg, rgba(233,228,214,.055), rgba(233,228,214,.02));
  border-color:rgba(233,228,214,.13); border-left-color:var(--rust);
  box-shadow:var(--edge);}
html[data-theme="dark"] .scenario-flag{
  background:#16291F; border-color:rgba(233,228,214,.16); color:#9AA79F;}
html[data-theme="dark"] .photo-quote blockquote{color:#D3DBD5;}



/* ===========================================================================
   STATEMENT CHART
   A stock-ticker line running behind "that question has no honest answer".

   The whole thing is one color — currentColor on the <svg> — so the line,
   the area gradient, the gridlines and the head dot all move together when
   the theme flips, instead of being four values to keep in step.
   =========================================================================== */

.stmt-chart{position:absolute; inset:0; z-index:-1; width:100%; height:100%;
  pointer-events:none; color:var(--brass);
  /* Faded hardest where the words sit. Without this the line runs straight
     through the sentence and the sentence loses. */
  -webkit-mask-image:radial-gradient(58% 62% at 50% 46%, transparent 8%, #000 82%);
  mask-image:radial-gradient(58% 62% at 50% 46%, transparent 8%, #000 82%);
  opacity:.5;}
html[data-theme="dark"] .stmt-chart{opacity:.62;}

.stmt-chart .grid line{stroke:currentColor; stroke-width:1; opacity:.14;
  stroke-dasharray:3 7; vector-effect:non-scaling-stroke;}

/* The draw-in. 3600 is comfortably longer than the path, so the dash gap
   clears the whole line; measuring it exactly would need JS for no gain. */
.stmt-line{stroke-dasharray:3600; stroke-dashoffset:3600;
  transition:stroke-dashoffset 2.6s cubic-bezier(.33,.72,.36,1) .25s;}
[data-motion].in .stmt-line{stroke-dashoffset:0;}

/* The fill rises from the baseline a beat behind the line, so you read the
   line arriving first and the volume filling in under it. */
.stmt-area{opacity:0; transform:scaleY(.55); transform-origin:50% 100%;
  transition:opacity 1.1s ease .5s, transform 1.9s cubic-bezier(.22,.85,.3,1) .5s;}
[data-motion].in .stmt-area{opacity:1; transform:scaleY(1);}

/* The head dot appears only once the line has reached it, then keeps a slow
   pulse — the "still ticking" beat every live chart has. */
.stmt-head{opacity:0; transition:opacity .4s ease 2.7s;}
[data-motion].in .stmt-head{opacity:1; animation:stmtPing 2.8s ease-in-out 3.1s infinite;}
@keyframes stmtPing{
  0%,100%{r:5; filter:drop-shadow(0 0 0 rgba(215,165,68,0));}
  50%    {r:6; filter:drop-shadow(0 0 7px rgba(215,165,68,.75));}
}

@media (max-width:640px){
  .stmt-chart{opacity:.34;
    -webkit-mask-image:radial-gradient(70% 70% at 50% 46%, transparent 4%, #000 88%);
    mask-image:radial-gradient(70% 70% at 50% 46%, transparent 4%, #000 88%);}
}

@media (prefers-reduced-motion: reduce){
  .stmt-line{stroke-dashoffset:0 !important; transition:none;}
  .stmt-area{opacity:1 !important; transform:none !important; transition:none;}
  .stmt-head{opacity:1 !important; transition:none; animation:none !important;}
}

/* ===========================================================================
   ORPHANS AND WIDOWS
   A heading that drops its last word onto a line of its own is the single
   most common way good copy looks unfinished. Two different tools, because
   headings and body copy have different failure modes:

     text-wrap:balance  — evens out the line lengths across the whole block.
                          Right for headings, which are short and where a
                          ragged last line is what you actually see. The spec
                          caps it at a handful of lines, so it costs nothing
                          on long text because it simply doesn't apply.
     text-wrap:pretty   — leaves the line breaking alone but refuses to strand
                          a single word on the last line. Right for paragraphs,
                          where balancing would visibly shorten every line.

   Both are progressive enhancement: unsupported browsers ignore the
   declaration and wrap as before. theme.js carries a fallback that inserts a
   non-breaking space for those, so nothing depends on this alone.
   =========================================================================== */

/* Every element that can BE a heading, rather than a list of the classes that
   happened to be headings when this was written. That list was the bug: it
   named .feature-card h3 and .trial-step h3 and .pc-name, but how-it-works
   carries its own stylesheet using .tcard b and .step h3 — none of which
   matched — so that page had no balancing at all, and its card titles stranded
   single words. A curated list only protects the pages someone remembered.

   b and strong are safe here. text-wrap applies to block containers, so an
   inline <b> mid-sentence is unaffected; it takes effect only where a <b> has
   been set display:block to act as a card title, which is the pattern used all
   over this site. Browsers stop balancing after a handful of lines, so long
   prose is left alone. */
h1, h2, h3, h4, h5, h6,
summary, figcaption, blockquote, dt, caption, legend,
b, strong,
.lede, .statement p, .sec-head p, .viz-title, .viz-sub,
.pc-blurb, .pc-terms, .price-panel .price-list li, .device-note,
.cap p, .mega a.mega-link span{
  text-wrap:balance;}

p, li, dd, .faq-a, .photo-credit span, .feat-list li,
.footer-brand p, .hero-micro, .micro, .pc-note, .price-foot,
.statband span, .tcard p{
  text-wrap:pretty;}

/* Two strings that must never break at all, wherever they appear. */
.brand-word, .pc-price, .price-amount, .stat b, .statband b{
  white-space:nowrap;}

/* ===========================================================================
   BILLING TOGGLE
   One attribute — data-billing on the panel — drives every swap. Both sets of
   figures are in the markup and CSS hides one, so switching is instant, the
   yearly numbers are readable with CSS disabled, and there is no JS template
   that can drift out of sync with the prices in the HTML.
   =========================================================================== */

.bill-toggle{display:inline-flex; align-items:stretch; gap:4px; margin:0 auto 26px;
  padding:4px; border-radius:999px; border:1.5px solid var(--line);
  background:var(--paper-card); box-shadow:var(--lift-1);}
.bill-toggle{display:flex; width:max-content;}
.price-panel + .price-foot, .bill-toggle{margin-left:auto; margin-right:auto;}

.bt-opt{display:inline-flex; align-items:center; gap:8px; cursor:pointer;
  font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:14px;
  padding:9px 18px; border-radius:999px; border:1px solid transparent;
  background:transparent; color:var(--grey);
  transition:background .2s var(--ease-out), color .2s var(--ease-out),
             box-shadow .2s var(--ease-out);}
.bt-opt:hover{color:var(--head);}
.bt-opt[aria-pressed="true"]{background:var(--pine); color:var(--on-dark);
  box-shadow:0 2px 8px rgba(30,61,47,.22);}
.bt-opt:focus-visible{outline:2px solid var(--brass); outline-offset:2px;}

.bt-save{font-family:'IBM Plex Mono', monospace; font-size:10.5px; font-weight:600;
  letter-spacing:.07em; text-transform:uppercase;
  padding:3px 8px; border-radius:999px;
  background:rgba(184,134,43,.16); color:#8A6417;
  border:1px solid rgba(184,134,43,.32);}
.bt-opt[aria-pressed="true"] .bt-save{background:rgba(244,239,225,.18);
  color:var(--on-dark); border-color:rgba(244,239,225,.34);}

html[data-theme="dark"] .bill-toggle{
  background:linear-gradient(180deg,#1A2E23,#16291F);
  border-color:rgba(233,228,214,.16); box-shadow:var(--edge);}
html[data-theme="dark"] .bt-opt{color:#9AA79F;}
html[data-theme="dark"] .bt-opt:hover{color:var(--head);}
html[data-theme="dark"] .bt-opt[aria-pressed="true"]{
  background:linear-gradient(180deg,#E0AE4E,#C99433); color:#16210C;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 3px 10px rgba(215,165,68,.28);}
html[data-theme="dark"] .bt-save{background:rgba(215,165,68,.18); color:#E8C077;
  border-color:rgba(215,165,68,.36);}
html[data-theme="dark"] .bt-opt[aria-pressed="true"] .bt-save{
  background:rgba(22,33,12,.22); color:#16210C; border-color:rgba(22,33,12,.3);}

/* ---- the swap ----
   Default to yearly, since that is what the panel ships with. Both branches
   are explicit rather than relying on one being the fallback, so the markup
   can't render both at once for a frame before the attribute is read. */
.price-panel .m, .price-panel .y{display:none;}
.price-panel[data-billing="monthly"] .m{display:inline;}
.price-panel[data-billing="yearly"]  .y{display:inline;}
.pc-from .m, .pc-from .y{display:none;}
.price-panel[data-billing="monthly"] .pc-from .m,
.price-panel[data-billing="yearly"]  .pc-from .y{display:inline;}

/* The price itself gets a small lift when it changes, so the eye is told
   something moved rather than having to notice a different number. */
.pc-price span{display:inline-block;}
.price-panel.bill-swap .pc-price span{
  animation:priceSwap .42s cubic-bezier(.22,.85,.3,1);}
@keyframes priceSwap{
  from{opacity:0; transform:translateY(7px);}
  to  {opacity:1; transform:none;}
}

@media (max-width:560px){
  .bill-toggle{width:100%; justify-content:stretch;}
  .bt-opt{flex:1; justify-content:center; padding:10px 10px; font-size:13px;}
  .bt-save{font-size:9.5px; padding:2px 6px;}
}
@media (prefers-reduced-motion: reduce){
  .price-panel.bill-swap .pc-price span{animation:none;}
  .bt-opt{transition:none;}
}

/* FAQ rows inside a light banner. .faq-dark's rules are scoped to that class,
   but the pricing FAQ uses .band-light instead — these give it the light-page
   treatment explicitly rather than relying on what it happens to inherit. */
html[data-theme="dark"] .band-light .faq details{
  border-top:1.5px solid var(--line); border-left:0; border-right:0;
  border-bottom:0; border-radius:0; background:transparent;
  padding:18px 0; margin-bottom:0; box-shadow:none;}
html[data-theme="dark"] .band-light .faq details:last-child{
  border-bottom:1.5px solid var(--line);}
html[data-theme="dark"] .band-light .faq details:hover{
  background:transparent; transform:none;}
html[data-theme="dark"] .band-light .faq details[open]{
  background:transparent; border-color:var(--line);}
html[data-theme="dark"] .band-light .faq summary{color:var(--head);}
html[data-theme="dark"] .band-light .faq summary::after{color:var(--rust);}
html[data-theme="dark"] .band-light .faq .faq-a{color:var(--ink);}
html[data-theme="dark"] .band-light .faq .faq-a a{color:var(--rust);}
html[data-theme="dark"] .band-light .sec-head .tag{color:var(--head);}

/* ---------------------------------------------------------------------------
   NO STRANDED GRID ITEMS
   auto-fit is the wrong tool for a KNOWN number of items. It optimizes for
   filling the available width and is indifferent to whether the final row
   looks finished, so it will happily leave one card alone under a full row —
   which reads as a mistake or a missing item rather than as the last peer.
   Where the count is known, the column count is stated and chosen so it
   divides: 4 -> 4/2/1, 5 -> 5/3/1, 9 -> 3/2 (never 4), 8 -> 4/2.
   --------------------------------------------------------------------------- */
@media (max-width:620px){ .split-key{grid-template-columns:repeat(2,1fr);} }
@media (max-width:380px){ .split-key{grid-template-columns:1fr;} }

/* ---------------------------------------------------------------------------
   SPLIT STAGE — the hero composition, reused mid-page
   Same classes as the hero so there is one phone, one popout and one stage in
   the codebase rather than a second near-copy that drifts. Only the scale and
   the frame differ: this sits inside a step's text column, not a full-bleed
   hero, so it is shorter and the popouts pull in closer to the device.
   --------------------------------------------------------------------------- */
.split-stage{margin:26px 0 28px; border-radius:18px; overflow:hidden;
  border:1.5px solid var(--line); min-height:auto;}
.split-stage .stage-devices{padding:34px 0 30px; transform:scale(.86);
  transform-origin:center;}
/* 186px is not enough for these three: "Tax moved first" plus "$1,890" in the
   meta needs more, so the title ran underneath its own value. Same failure as
   the hero cards had, same fix -- one fixed width wide enough for the longest
   pair, and every card the same so they do not read as three components. */
.split-stage .popout{width:238px; max-width:none;}
.split-stage .po-body b{font-size:12px;}
.split-stage .po-body span{font-size:10px;}
@media (max-width:760px){
  /* Below this the popouts would sit on top of the phone rather than beside
     it. The phone alone still carries the idea — the split is visible on the
     screen itself — so the cards go rather than overlap. */
  .split-stage .popout{display:none;}
  .split-stage .stage-devices{transform:scale(.94); padding:22px 0 18px;}
}

/* The fourteen-day track inside the trial stage. */
.trial-track{margin:14px 0 16px;}
.trial-track .tt-bar{display:block; height:6px; border-radius:99px;
  background:rgba(30,61,47,.12); overflow:hidden;}
.trial-track .tt-bar i{display:block; height:100%; width:0; border-radius:99px;
  background:linear-gradient(90deg, var(--pine) 0%, var(--brass) 78%, var(--rust) 100%);
  transition:width 1.5s cubic-bezier(.22,.85,.3,1);}
.trial-track .tt-marks{display:flex; justify-content:space-between; margin-top:8px;}
.trial-track .tt-marks span{display:flex; flex-direction:column; align-items:center;
  font-family:var(--mono); font-size:8.5px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--grey);}
.trial-track .tt-marks b{font-size:12px; color:var(--head); margin-bottom:1px;}

/* ---------------------------------------------------------------------------
   PAGE-TOP EYEBROW + RULE
   The shape the home page and how-it-works already use — a small mono label,
   a short rust rule, then the headline. Three content pages opened straight on
   an h1 with no label, so a reader landing from search had no idea whether
   they were on a guide, a comparison or a product page until they had read a
   paragraph. The label is the cheapest orientation a page can offer.

   Deliberately NOT applied to 404 and thank-you: 404 already opens with
   "404 — page not found", which is the same device doing the same job, and
   thank-you is a one-line confirmation where a category label would be
   ceremony. Consistent does not mean identical — it means the same pattern
   wherever the pattern has something to say.
   --------------------------------------------------------------------------- */
.page-eyebrow{font-family:var(--mono); font-size:11.5px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--rust); font-weight:600; margin:0 0 10px;}
.page-rule{width:56px; height:3px; border:0; border-radius:2px;
  background:var(--rust); margin:0 0 18px;}
.article-head .page-eyebrow{margin-top:0;}

/* Visually hidden, still announced. Used where a section needs a heading for
   the document outline but showing it would repeat what the page already says
   — the guides index already has "Money, explained without the jargon" as its
   h1; a visible "All guides" above the cards would be noise. The outline still
   needs the level, because a screen reader builds its table of contents from
   headings and a jump from h1 straight to h3 reads as a missing section. */
.sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;}

/* ===========================================================================
   EDITORIAL LAYER — guides only
   Added 2 Sep. The articles were structurally correct and visually flat: a
   heading, some paragraphs, a picture, repeat. Everything here earns its place
   by doing a job at a specific point in a long read, rather than decorating
   uniformly. All of it degrades to plain text if the CSS never loads.
   =========================================================================== */

/* ---- 1. Drop cap ---------------------------------------------------------
   Marks where the article proper begins. The lede is a summary; this is the
   start of the argument, and on a 2,000-word page the reader benefits from
   being told which is which.

   ::first-letter on the paragraph right after the lede, so nothing has to be
   marked up. The negative top margin is the fiddly part: a glyph this size
   carries its own leading, and without pulling it up the cap sits a few pixels
   below the x-height of the line it belongs to and reads as a mistake. */
.article-body .article-lede + p::first-letter{
  float:left; font-family:'Fraunces', Georgia, serif; font-weight:600;
  font-size:60px; line-height:.86; margin:6px 10px -2px 0;
  color:var(--rust);}
/* Never on a paragraph that opens with a quotation mark or a number — a
   floated 60px quote mark is a hole in the page, and a floated digit reads as
   a list marker. */
.article-body .article-lede + p.no-cap::first-letter{
  float:none; font:inherit; color:inherit; margin:0;}

/* ---- 2. Section marks ----------------------------------------------------
   A short brass rule above every h2. Numbers were the other option and were
   wrong here: these are guides people arrive at mid-page from search, and
   "03" on the first thing you see implies you have missed something. A rule
   just says "new section" without making a claim about sequence. */
.article-body h2{position:relative; padding-top:20px;}
.article-body h2::before{content:""; position:absolute; top:0; left:0;
  width:34px; height:3px; border-radius:2px; background:var(--brass);}

/* ---- 3. Pull quote -------------------------------------------------------
   For the sentence that carries the argument. Sits outside the measure on the
   left so it interrupts the column — the point of a pull quote is that the eye
   catches it while scrolling past, which a centered box does not achieve. */
.article-body .pull{margin:32px 0; padding:4px 0 4px 22px;
  border-left:3px solid var(--rust);
  font-family:'Fraunces', Georgia, serif; font-size:22px; line-height:1.4;
  color:var(--head); font-weight:600; text-wrap:balance;}
.article-body .pull p{margin:0;}
.article-body .pull cite{display:block; margin-top:10px;
  font-family:var(--mono); font-size:11.5px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--grey); font-style:normal; font-weight:400;}
/* The hanging version of this — margin-left:-56px above 1080px — was removed on
   6 Sep. It is a real editorial device, but on this page it fought the Brass Tax
   panel and the charts, which stay in the column: the eye reads two different
   left edges as a mistake rather than as emphasis. Alignment beats the flourish
   when the page has panels in it. */

/* ---- 4. Figures sit in the column ----------------------------------------
   These used to break out above 1080px: width calc(100% + 112px) with a -56px
   left margin, on the theory that a photograph held to the text measure looks
   timid.

   REMOVED 6 Sep, because it was wrong here. The guides are not pure prose —
   every one carries a Brass Tax panel, a chart and a sources block, and all of
   those sit in the column. A hero that overhangs them by 56px on each side does
   not read as rhythm, it reads as a broken container, which is exactly what it
   looked like. Every block in the article now shares one left edge and one
   right edge.

   If the breakout ever comes back it has to take the panels with it, or the
   mismatch comes back too. */

/* ---- 5. End mark ---------------------------------------------------------
   The old printer's device for "the article is over". Useful here because
   every guide is followed by related links, a help block and a disclaimer —
   without a terminator the reader cannot tell where the writing stops and the
   furniture starts. */
.article-body .article-end{display:block; width:12px; height:12px;
  margin:26px 0 30px; border-radius:3px; background:var(--brass);
  transform:rotate(45deg);}

/* ---- 6. Reading progress -------------------------------------------------
   A brass hairline across the top. On a long guide the browser scrollbar is
   the only progress signal and it measures the whole document — including the
   footer — so it always overstates how much reading is left. This measures the
   article element only, which is the thing being read.
   Painted by motion.js; with JS off the bar simply never appears. */
.read-bar{position:fixed; top:0; left:0; height:3px; width:0;
  background:linear-gradient(90deg, var(--brass), var(--rust));
  z-index:1200; pointer-events:none; transition:width .08s linear;}
@media (prefers-reduced-motion: reduce){ .read-bar{transition:none;} }
@media print{ .read-bar{display:none;} }
