/* ===========================================================================
   COMPONENTS — SHARED BY EVERY PAGE
   Extracted 2026-08-29 to end a specific, repeating class of bug.

   Two pages (how-it-works.html, support-center.html) carry their own complete
   stylesheets rather than linking styles.css. Every shared component therefore
   existed in two or three copies, and three separate bugs in one session were
   "fixed in one file, still broken in the other" — the mega-menu dark panel,
   the nav trigger typography, and the --cream text/surface split.

   Anything in this file is used by BOTH kinds of page, so it lives ONCE and
   every page links it. It depends only on custom properties (--mono, --head,
   --line, --rust, --brass, --edge…) which each page's own :root supplies, so
   it drops into either context without knowing which it is in.

   Rule of thumb: if a component appears on a page that has its own stylesheet,
   it belongs here. If it only ever appears on the styles.css pages, leave it
   in styles.css.
   =========================================================================== */

/* ===========================================================================
   MEGA-MENU — CANONICAL BLOCK
   This exact text lives in two places: styles.css (for the nine pages that
   link it) and inside how-it-works.html (which carries its own stylesheet).
   They had drifted — different dark-panel backgrounds, and the column cascade
   and feature-card hover existed on one page only — so Product and Resources
   looked subtly different depending on where you opened them.

   If you change anything here, change it in BOTH copies. There is no build
   step to keep them in sync, and a diff of these two blocks is the only test.
   =========================================================================== */

/* Hover opens it on a mouse; click opens it on touch and for keyboards. Both
   paths set the same [data-open] attribute, so there is one visual state to
   reason about rather than a :hover rule and a class fighting each other. */
.has-mega{position:relative;}
/* Desktop only. Making .has-mega static hands the containing block to the nav
   row, so an 880px panel centers on the 1080px container instead of on its
   trigger — a trigger near the right edge would otherwise push the panel off
   the viewport, and pages that clip overflow guillotine it rather than
   scrolling. Below 900px the panel is a static list and needs no anchor. */
@media (min-width:861px){
  .navin, .site-nav .container{position:relative;}
  .has-mega{position:static;}
}

.mega-trigger{display:inline-flex; align-items:center; gap:5px; background:none;
  border:0; padding:0; font:inherit; color:inherit; cursor:pointer;}
.mega-trigger::after{content:""; width:6px; height:6px; margin-top:-3px;
  border-right:1.6px solid currentColor; border-bottom:1.6px solid currentColor;
  transform:rotate(45deg); transition:transform .18s ease;}
.has-mega[data-open] .mega-trigger::after{transform:rotate(-135deg); margin-top:2px;}

.mega{position:absolute; top:calc(100% + 14px); left:50%;
  transform:translateX(-50%) translateY(-6px);
  width:min(880px, calc(100vw - 40px)); max-width:100%;
  background:var(--paper-card);
  border:1.5px solid var(--line); border-radius:14px;
  box-shadow:0 24px 60px rgba(30,61,47,.16); padding:26px;
  display:grid; grid-template-columns:1fr 1fr 250px; gap:26px;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .18s ease, transform .18s ease, visibility .18s;
  z-index:910;}
.has-mega[data-open] .mega{opacity:1; visibility:visible; pointer-events:auto;
  transform:translateX(-50%) translateY(0);}
/* Bridges the 14px gap so the pointer can travel from trigger to panel without
   crossing dead space and closing it — the classic mega-menu bug. */
.mega::before{content:""; position:absolute; top:-16px; left:0; right:0;
  height:16px; pointer-events:auto;}

/* Columns cascade in behind the panel rather than arriving with it. */
.mega > *{opacity:0; transform:translateY(6px);
  transition:opacity .22s ease, transform .28s ease;}
.has-mega[data-open] .mega > *{opacity:1; transform:none;}
.has-mega[data-open] .mega > *:nth-child(1){transition-delay:.04s;}
.has-mega[data-open] .mega > *:nth-child(2){transition-delay:.09s;}
.has-mega[data-open] .mega > *:nth-child(3){transition-delay:.14s;}

.mega h4{font-family:var(--mono); font-size:11px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--rust); margin:0 0 12px; font-weight:600;}
.mega a.mega-link{display:block; text-decoration:none; padding:8px 10px;
  margin:0 -10px; border-radius:8px; transition:background .12s;}
.mega a.mega-link:hover{background:var(--pine-soft);}
/* Title in caps, description in sentence case.
   Uppercase needs three compensations or it reads as shouting rather than as a
   label: drop the size (caps occupy more width and more optical weight at the
   same point size), open the tracking (letterforms set solid at cap height
   crowd each other), and switch to the mono face, which is drawn for this and
   already carries the nav's voice. The description underneath stays sentence
   case — it is a sentence, and running it in caps would destroy the very
   contrast that makes the title read as a heading. */
.mega a.mega-link b{display:block; font-family:var(--mono); font-size:12px;
  letter-spacing:.09em; text-transform:uppercase; color:var(--head);
  font-weight:600; margin-bottom:4px; line-height:1.3;}
.mega a.mega-link span{display:block; font-family:var(--sans); font-size:12.5px;
  color:var(--grey); line-height:1.45; text-transform:none; letter-spacing:0;}
/* Balance the wrap as well as gluing the last two words in the markup — the
   columns are narrow enough that a three-line description can strand a word
   in the middle of the block, which &nbsp; on the tail does not catch. */
.mega h4, .mega a.mega-link b, .mega a.mega-link span,
.mega-feature .cap p, .mega-feature .cap a{text-wrap:balance;}

.mega-feature{background:var(--cream); border:1.5px solid var(--line);
  border-radius:12px; overflow:hidden; display:flex; flex-direction:column;
  transition:transform .25s cubic-bezier(.22,.85,.3,1);}
.mega-feature:hover{transform:translateY(-2px);}
/* No aspect-ratio. A fixed ratio makes the image assert its own height, so the
   card becomes the tallest thing in the row and stretches the panel past the
   link columns. flex:1 1 0 with min-height:0 means it contributes nothing to
   the card's natural height: the lists set the row, the image fills the rest. */
/* The card is a SHORT letterbox — the link columns set the row height and the
   image takes whatever is left above the caption — so cover crops top and
   bottom around object-position's Y. At the default 50% the visible band
   starts around 25% down the frame, which is below both subjects' heads:
   the plumber's starts at 17.8%, the videographer's at 10.4%.

   Per-image Y values measured off the actual frames rather than guessed, with
   enough margin that the crop still clears their heads when the panel is
   short. min-height stops the image collapsing to a sliver, which is what
   makes any crop look severe. */
.mega-feature .shot{flex:1 1 0; min-height:132px; width:100%; object-fit:cover;
  display:block; border-bottom:1.5px solid var(--line);
  background:var(--pine-soft); object-position:50% 22%;}
.mega-feature .shot[src*="plumber"]{object-position:50% 20%;}
.mega-feature .shot[src*="videographer"]{object-position:50% 14%;}
.mega-feature .cap{padding:14px 16px 16px;}
.mega-feature .cap p{margin:0 0 10px; font-size:13px; line-height:1.5;
  color:var(--ink);}
.mega-feature .cap a{font-family:var(--mono); font-size:11.5px;
  letter-spacing:.06em; text-transform:uppercase; font-weight:600;
  color:var(--rust); text-decoration:none;}
.mega-feature .cap a:hover{text-decoration:underline;}

/* ---- dark ---- */
html[data-theme="dark"] .mega{
  background:linear-gradient(180deg,#20372A 0%, #182C21 100%);
  border-color:rgba(233,228,214,.16);
  box-shadow:var(--edge-strong), 0 24px 60px rgba(0,0,0,.55);}
html[data-theme="dark"] .mega a.mega-link:hover{background:rgba(233,228,214,.07);}
html[data-theme="dark"] .mega a.mega-link b{color:var(--head);}
html[data-theme="dark"] .mega a.mega-link span{color:#9FAFA5;}
html[data-theme="dark"] .mega h4{color:#E8A882;}
html[data-theme="dark"] .mega-feature{background:rgba(233,228,214,.04);}
html[data-theme="dark"] .mega-feature .cap p{color:#CBD6CE;}
html[data-theme="dark"] .mega-feature .shot{filter:brightness(.92) saturate(.96);}
html[data-theme="dark"] .mega-trigger{color:#D3DBD5;}

/* 860px, NOT 900px — it must be the SAME width at which the nav itself
   collapses (.nav-toggle appears and .nav-panel hides at max-width:860px).
   They were 40px apart, and in that 40px window the desktop nav was still a
   76px flex row while .mega had already become position:static. Opening
   Product or Resources dropped a full static panel into that row, on top of
   everything below it: the overlapping, unreadable text.

   If the nav breakpoint ever moves, this one moves with it. */
@media (max-width:860px){
  /* Below the breakpoint the nav collapses, so the panel becomes a plain
     nested list — no absolute positioning, no hover, no cascade. */
  .mega{position:static; transform:none; width:auto; grid-template-columns:1fr;
    opacity:1; visibility:visible; pointer-events:auto; box-shadow:none;
    border:0; padding:6px 0 10px; background:transparent; display:none;}
  .has-mega[data-open] .mega{display:block; transform:none;}
  .mega > *{opacity:1; transform:none; transition:none;}
  .mega-feature{display:none;}
}
@media (prefers-reduced-motion: reduce){
  .mega, .mega > *, .mega-feature, .mega-trigger::after{transition:none !important;}
  .mega > *{opacity:1; transform:none;}
  .mega-feature:hover{transform:none;}
}

/* ---- draft-only theme toggle ---------------------------------------------
   Review affordance, not a shipped feature. Delete this block and the button
   in index.html together. */
/* The button PREVIEWS the theme it will switch you to, rather than matching
   the one you are already looking at. It says "Dark", so it is dark. It says
   "Light", so it is white. Before this it did the opposite — a white chip
   labeled "Dark" on a white page, which reads as a state indicator, not a
   switch, and gives you nothing you did not already know. */
.theme-toggle{position:fixed; right:18px; bottom:18px; z-index:2000;
  display:inline-flex; align-items:center; gap:9px;
  background:#12211A; color:#F1EDE1;
  border:1.5px solid rgba(233,228,214,.22); border-radius:999px;
  padding:8px 15px 8px 11px; cursor:pointer;
  box-shadow:0 2px 4px rgba(30,61,47,.07), 0 12px 28px rgba(30,61,47,.09);
  font-family:'IBM Plex Mono', monospace; font-size:11px; letter-spacing:.08em;
  text-transform:uppercase; font-weight:600;
  transition:border-color .2s ease, transform .18s cubic-bezier(.34,1.4,.64,1);}
.theme-toggle:hover{border-color:#B8862B; transform:translateY(-2px);}
.theme-toggle:active{transform:translateY(0);}
.theme-toggle:focus-visible{outline:2px solid #B8862B; outline-offset:3px;}

/* THE CHIP FLIPS. This rule was missing here while the live waitlist page has
   had it all along, and its absence was not cosmetic — it was the whole idea
   failing silently on half the site.

   The button previews the theme it switches you TO. On a light page it is dark
   and offers the moon; on a dark page it must go white and offer the sun.
   Without this rule the chip stayed #12211A on dark pages, so the sun sat at
   #8A6417 on a near-black pill: 3.11:1, which scrapes past the 3:1 minimum for
   a non-text graphic by accident rather than by design, and reads as a dim
   smudge. On the white chip the same sun is 5.13:1.

   The dark brass is deliberate and stays: #D7A544 on white is only 2.15:1. */
html[data-theme="dark"] .theme-toggle{background:#FBFAF6; color:#14251C;
  border-color:rgba(20,37,28,.16);
  box-shadow:0 2px 6px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.9);}

/* Both icons occupy the same 18px cell; only one is visible at a time. The
   incoming icon rotates in as the outgoing one rotates out, which is what
   makes this read as a switch being thrown rather than a picture being
   replaced. */
.tt-icons{position:relative; width:18px; height:18px; flex:none; display:block;}
.tt-icons .ic{position:absolute; inset:0; width:18px; height:18px;
  transition:opacity .28s ease, transform .38s cubic-bezier(.34,1.4,.64,1);}
/* Light page: offer the moon. */
/* On the light page the chip is dark, so the moon needs a light-on-dark
   brass. On the dark page the chip is white, so the sun needs a DARKER brass —
   #D7A544 on white is 2.15:1, below the 3:1 minimum for a non-text element. */
.ic-sun{opacity:0; transform:rotate(-90deg) scale(.5); color:#8A6417;}
.ic-moon{opacity:1; transform:rotate(0) scale(1); color:#D7A544;}
/* Dark page: offer the sun. */
html[data-theme="dark"] .ic-sun{opacity:1; transform:rotate(0) scale(1); color:#8A6417;}
html[data-theme="dark"] .ic-moon{opacity:0; transform:rotate(90deg) scale(.5);}
/* Hover must only grow the icon that is actually showing. A blanket
   `.theme-toggle:hover .ic{transform:scale(1.12)}` also resets the hidden
   icon's rotation, so the invisible one animates back into place behind the
   visible one and the crossfade tears. Four explicit rules, light first then
   the dark overrides. */
.theme-toggle:hover .ic-moon{transform:rotate(0) scale(1.12);}
.theme-toggle:hover .ic-sun{transform:rotate(-90deg) scale(.5);}
html[data-theme="dark"] .theme-toggle:hover .ic-sun{transform:rotate(0) scale(1.12);}
html[data-theme="dark"] .theme-toggle:hover .ic-moon{transform:rotate(90deg) scale(.5);}

@media (max-width:520px){
  /* Icon only — the word is the first thing worth losing on a narrow screen,
     and the aria-label carries the meaning regardless. */
  .theme-toggle{padding:9px; right:20px;
    /* Off the corner, and clear of the home indicator / in-app browser bar.
       env() resolves to 0 where there is no inset, so one rule covers both. */
    bottom:calc(22px + env(safe-area-inset-bottom, 0px));}
  .tt-label{display:none;}
  /* A fixed button has no height for the footer to push against, so it sits on
     top of whatever the last scroll position leaves under it. Reserve the
     space rather than hoping the footer is short enough. */
  body{padding-bottom:calc(88px + env(safe-area-inset-bottom, 0px));}
}

/* Both ported from the live waitlist page so the two behave identically.
   Reduced motion keeps the crossfade — which carries the meaning — and drops
   the rotation and lift, which are decoration. Print drops the button
   entirely: it is a control, and a control on paper is just ink. */
@media (prefers-reduced-motion: reduce){
  .theme-toggle, .tt-icons .ic{transition:opacity .15s ease; transform:none !important;}
}
@media print{ .theme-toggle{display:none;} }
@media (prefers-reduced-motion: reduce){
  .tt-icons .ic{transition:opacity .15s ease; transform:none !important;}
}
@media print{ .theme-toggle{display:none;} }

/* ---- scroll progress bar (injected by theme.js) --------------------------
   Sits above the sticky nav rather than under it — a progress indicator behind
   the header is a progress indicator nobody sees. Rust on light, brass on
   dark: on the near-black page rust loses too much against the header. */
#prog{position:fixed; top:0; left:0; height:3px; width:0; z-index:1000;
  background:linear-gradient(90deg, var(--rust), #D06A3E);
  box-shadow:0 0 10px rgba(181,75,42,.45); pointer-events:none;
  border-radius:0 2px 2px 0;}
html[data-theme="dark"] #prog{
  background:linear-gradient(90deg, #C79231, var(--brass));
  box-shadow:0 0 12px rgba(215,165,68,.55);}



/* ===========================================================================
   MOTION LAYER
   Added 2026-08-29. Everything here is an enhancement: with the feature
   unsupported, or reduced-motion on, the page is already in its final state.
   Nothing below gates content on script.

   Three rules I held to, because "sleek" becomes "restless" fast:
     · Motion answers a question. Arriving = this is new. Lifting = this is
       clickable. A shrinking nav = you have moved. Anything answering nothing
       was cut.
     · Nothing loops in the reading column. Loops belong in the hero art, where
       the eye is already parked — not beside a paragraph someone is reading.
     · Under 400ms, or it is in the way. The scroll-linked ones have no
       duration at all: they are tied to position, so they feel instant.
   =========================================================================== */

/* ---- scroll-linked reveals ----------------------------------------------
   animation-timeline:view() ties the animation to the element's position in
   the viewport rather than to a clock. No IntersectionObserver, nothing on the
   main thread, and scrubbing backwards works free when you scroll up.
   @supports guards it: where unsupported the keyframes never run and the
   elements simply sit at their normal values. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal{
      animation:revealIn linear both;
      animation-timeline:view();
      animation-range:entry 8% cover 26%;
    }
    @keyframes revealIn{
      from{opacity:0; transform:translateY(22px);}
      to  {opacity:1; transform:none;}
    }

    /* Children arrive in sequence rather than as a block.
       :nth-child, NOT a --i custom property written into every element. The
       property version means mutating the markup of every card on every page
       by automated pass — which is exactly how an unclosed <div> got into
       index.html earlier today. Six selectors in one file cannot corrupt
       anything, and the seventh child onward shares the last delay, which
       nobody will ever notice. */
    .reveal-stagger > *{
      animation:revealIn linear both;
      animation-timeline:view();
      animation-range:entry 6% cover 24%;
    }
    .reveal-stagger > :nth-child(2){animation-range:entry 9%  cover 27%;}
    .reveal-stagger > :nth-child(3){animation-range:entry 12% cover 30%;}
    .reveal-stagger > :nth-child(4){animation-range:entry 15% cover 33%;}
    .reveal-stagger > :nth-child(5){animation-range:entry 18% cover 36%;}
    .reveal-stagger > :nth-child(n+6){animation-range:entry 21% cover 39%;}
  }
}

/* ---- the nav condenses once you leave the top ---------------------------
   Set by theme.js. Signals "you have moved" without a second indicator, and
   reclaims 14px of vertical space on the way down. */
.site-nav, nav.top{
  transition:background .28s ease, box-shadow .28s ease, border-color .28s ease;}
.site-nav .container, nav.top .navin{
  transition:height .28s cubic-bezier(.22,.85,.3,1);}
.site-nav.condensed .container, nav.top.condensed .navin{height:62px;}
.site-nav.condensed, nav.top.condensed{
  box-shadow:0 6px 24px rgba(20,43,33,.10);
  border-bottom-color:var(--line);}
html[data-theme="dark"] .site-nav.condensed,
html[data-theme="dark"] nav.top.condensed{
  background:rgba(10,23,16,.92);
  box-shadow:0 6px 26px rgba(0,0,0,.5);}
.brand .mark{transition:transform .28s cubic-bezier(.22,.85,.3,1);}
.site-nav.condensed .brand .mark, nav.top.condensed .brand .mark{transform:scale(.88);}

/* NO underline on the menu links. I added one and it was wrong: a mega-link is
   a TWO-LINE block — a title and a description — not a single line of text. An
   absolutely-positioned rule at bottom:5px inside that box lands on the last
   line of the description and draws straight through the words.

   The links already have a hover affordance: the whole row takes a background
   tint. That is the correct treatment for a block-level link, and it needs no
   extra element to overlap anything. Left as a note so this does not get
   "improved" back in.
*/

/* ---- cross-page transitions ---------------------------------------------
   Same-origin navigations cross-fade instead of flashing. One declaration in
   modern browsers, ignored entirely everywhere else. */
@view-transition{ navigation:auto; }

@media (prefers-reduced-motion: reduce){
  .reveal, .reveal-stagger > *{animation:none !important; opacity:1; transform:none;}
  .site-nav, nav.top, .site-nav .container, nav.top .navin,
  .brand .mark, .mega a.mega-link::after{transition:none !important;}
  @view-transition{ navigation:none; }
}

/* ---- guide figure + support block ---------------------------------------
   Shared by the three long-form guides. Lives here rather than in styles.css
   because the guides and how-it-works both use them, and how-it-works reads
   its own sheet last — one definition, both contexts. */
.guide-figure{margin:0 0 30px; border-radius:14px; overflow:hidden;
  border:1.5px solid var(--line); box-shadow:var(--lift-2); background:var(--pine-soft);}
.guide-figure img{display:block; width:100%; height:auto; aspect-ratio:16/9;
  object-fit:cover; object-position:50% 34%;}
.guide-figure figcaption{padding:13px 18px 15px; font-size:13.5px; line-height:1.55;
  color:var(--grey); border-top:1.5px solid var(--line); text-wrap:pretty;}
html[data-theme="dark"] .guide-figure{border-color:rgba(233,228,214,.14);
  box-shadow:var(--edge), 0 12px 32px rgba(0,0,0,.4);}
html[data-theme="dark"] .guide-figure img{filter:brightness(.92) saturate(.96);}
html[data-theme="dark"] .guide-figure figcaption{
  background:rgba(233,228,214,.04); border-top-color:rgba(233,228,214,.12);}

/* The help block. Deliberately NOT a marketing CTA — someone who reaches the
   end of a 1,300-word tax guide has a question, not an objection. It offers a
   human and a search box, and mentions the product once, last. */
.help-block{margin:40px 0 8px; padding:24px 26px; border-radius:16px;
  background:var(--paper-card); border:1.5px solid var(--line);
  border-left:3px solid var(--brass); box-shadow:var(--lift-1);}
.help-block h3{font-family:var(--serif); font-size:19px; color:var(--head);
  margin:0 0 8px;}
.help-block p{margin:0 0 16px; font-size:14.5px; line-height:1.6; color:var(--ink);
  max-width:58ch;}
.help-links{display:flex; flex-wrap:wrap; gap:10px;}
.help-links a{display:inline-flex; align-items:center; gap:8px;
  font-family:var(--mono); font-size:11.5px; letter-spacing:.06em;
  text-transform:uppercase; font-weight:600; text-decoration:none;
  padding:10px 16px; border-radius:999px;
  border:1.5px solid var(--line); color:var(--head); background:var(--cream);
  transition:transform .18s cubic-bezier(.34,1.4,.64,1), border-color .18s ease;}
.help-links a:hover{transform:translateY(-2px); border-color:var(--brass);}
.help-links a.primary{background:var(--brass); border-color:var(--brass); color:#1A1405;}
.help-note{margin:14px 0 0; font-size:12.5px; color:var(--grey);}
html[data-theme="dark"] .help-block{
  background:linear-gradient(180deg,#1A2E23,var(--s2)); border-color:rgba(233,228,214,.13);
  border-left-color:var(--brass); box-shadow:var(--edge), 0 10px 30px rgba(0,0,0,.35);}
html[data-theme="dark"] .help-links a{background:rgba(233,228,214,.06);
  border-color:rgba(233,228,214,.2); color:var(--head);}
html[data-theme="dark"] .help-links a.primary{background:linear-gradient(180deg,#E0AE4E,#C99433);
  border-color:#E0AE4E; color:#16210C;}
@media (prefers-reduced-motion: reduce){ .help-links a{transition:none;} }

/* ---- set-aside calculator ------------------------------------------------
   Lives in components.css because it is a component, and because the same
   widget belongs on the pricing and how-it-works pages later without being
   rebuilt. Depends only on tokens. */
.bw-calc{margin:30px 0; padding:26px 28px 24px; border-radius:18px;
  background:var(--paper-card); border:1.5px solid var(--line);
  box-shadow:var(--lift-2);}
.calc-head h3{font-family:var(--serif); font-size:21px; color:var(--head);
  margin:0 0 6px;}
.calc-head h3 em{font-style:italic; color:var(--rust);}
.calc-head p{margin:0 0 22px; font-size:14px; color:var(--grey); max-width:52ch;}

.calc-inputs{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);
  gap:22px 30px; align-items:start;}
@media (max-width:620px){ .calc-inputs{grid-template-columns:minmax(0,1fr);} }
.calc-field > span{display:block; font-family:var(--mono); font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--grey);
  font-weight:600; margin-bottom:8px;}
.calc-field small{display:block; margin-top:8px; font-size:12px; line-height:1.5;
  color:var(--grey); text-wrap:pretty;}
.calc-field output{color:var(--head); font-size:13px; letter-spacing:.04em;}

.calc-money{display:flex; align-items:center; gap:2px;
  border:1.5px solid var(--line); border-radius:10px; padding:0 14px;
  background:var(--cream); transition:border-color .18s ease, box-shadow .18s ease;}
.calc-money:focus-within{border-color:var(--brass);
  box-shadow:0 0 0 3px rgba(184,134,43,.18);}
.calc-money i{font-style:normal; font-family:var(--serif); font-size:24px;
  color:var(--grey);}
.calc-money input{flex:1; min-width:0; border:0; background:none; outline:none;
  font-family:var(--serif); font-weight:600; font-size:28px; color:var(--head);
  padding:12px 0; letter-spacing:-.01em;}

/* The slider is the point of this widget — 30% is a starting point, not a law,
   so the rate has to be something the reader can move. */
input[type=range]#calc-pct{width:100%; margin:14px 0 0; accent-color:var(--brass);
  height:6px;}
.calc-scale{display:flex; justify-content:space-between; margin-top:6px;}
.calc-scale i{font-style:normal; font-family:var(--mono); font-size:10px;
  letter-spacing:.06em; color:var(--grey);}

.calc-out{margin-top:24px; padding-top:22px; border-top:1.5px solid var(--line);}
.calc-label{display:block; font-family:var(--mono); font-size:10px;
  letter-spacing:.11em; text-transform:uppercase; color:var(--grey);
  font-weight:600; margin-bottom:3px;}
.calc-big b{font-family:var(--serif); font-weight:600; font-size:44px;
  line-height:1; letter-spacing:-.025em; color:var(--head); display:block;}
.calc-split{display:grid; grid-template-columns:repeat(3,1fr); gap:16px;
  margin-top:20px;}
@media (max-width:560px){ .calc-split{grid-template-columns:1fr 1fr;} }
.calc-split b{font-family:var(--mono); font-size:17px; font-weight:600;
  color:var(--head);}
.calc-per-dollar{margin:20px 0 0; font-size:14.5px; color:var(--ink);}
.calc-per-dollar b{font-family:var(--mono); color:var(--head);}
.calc-note{margin:20px 0 0; padding-top:16px; border-top:1px solid var(--line);
  font-size:12.5px; line-height:1.6; color:var(--grey); text-wrap:pretty;}
.calc-note b{color:var(--head);}

html[data-theme="dark"] .bw-calc{
  background:linear-gradient(180deg,#1A2E23,var(--s2));
  border-color:rgba(233,228,214,.13);
  box-shadow:var(--edge), 0 14px 36px rgba(0,0,0,.4);}
html[data-theme="dark"] .calc-money{background:rgba(233,228,214,.05);
  border-color:rgba(233,228,214,.2);}
html[data-theme="dark"] .calc-out,
html[data-theme="dark"] .calc-note{border-top-color:rgba(233,228,214,.13);}
@media (prefers-reduced-motion: reduce){ .calc-money{transition:none;} }


/* ---- BRASS TAX ------------------------------------------------------------
   The summary box at the top of a guide: the three or four things you would
   still know a week later if you read nothing else.

   Named for brass tacks — the essentials — with the pun the brand was always
   going to make. The icon is an actual tack, which is the part that tells a
   reader it is deliberate rather than a misspelling.

   It goes ABOVE the article body and below the hero, in the place a reader's
   eye lands first. That is the whole point: someone who arrived from a search
   result wants to know within four seconds whether this page answers their
   question, and a summary they have to scroll to find has already failed.

   Colour notes, measured rather than guessed:
   - Body ink on brass-soft is 13.56:1, headings 10.06:1.
   - Links inside the box use --head with a brass underline, NOT --rust.
     Rust on this background measures 4.43:1, which is under the 4.5 needed
     for body-size text. Pine is 10.06:1 and matches the related-guides
     treatment, so the box gains no new link style of its own.
   - Dark mode sits on --paper-card: body 12.06:1, headings 13.09:1. */
.brass-tax{margin:0 0 30px; padding:22px 26px 24px;
  background:var(--brass-soft); border:1.5px solid var(--brass);
  border-radius:var(--radius);}
.brass-tax h2{display:flex; align-items:center; gap:10px;
  margin:0 0 14px; padding:0; font-size:19px; color:var(--head);}
/* The section marks added to article h2s would put a brass rule above this
   one too, which reads as a divider inside a box that already has a border. */
.brass-tax h2::before{content:none;}
.brass-tax .tack{width:19px; height:19px; flex:none; color:var(--brass);}
.brass-tax ul{margin:0; padding:0 0 0 20px;}
.brass-tax li{margin:0 0 9px; font-size:15.5px; line-height:1.6;
  color:var(--ink); text-wrap:pretty;}
.brass-tax li:last-child{margin-bottom:0;}
.brass-tax li::marker{color:var(--brass);}
.brass-tax a{color:var(--head); font-weight:600; text-decoration:none;
  border-bottom:1.5px solid var(--brass);}
.brass-tax a:hover{border-bottom-width:2px;}

html[data-theme="dark"] .brass-tax{background:var(--paper-card);
  border-color:rgba(215,165,68,.42);}

@media (max-width:520px){
  .brass-tax{padding:18px 18px 20px;}
  .brass-tax h2{font-size:17px;}
  .brass-tax li{font-size:15px;}
}

/* ---- LOOKING FOR MORE -----------------------------------------------------
   Two-column tail block, replacing the separate related-guides list AND the
   help block. Those were two of four things stacked at the end of every guide
   — related links, ask-a-human, product CTA, disclaimer — and four blocks
   after the last sentence is where a reader stops reading rather than starts.

   Column one is other guides. Column two is everything that is not a guide:
   the Support Center, how the product works, a human. Splitting on that line
   rather than by topic is what lets column two stay useful while there are
   only a handful of articles — with four guides, a "more in this category"
   column would just repeat column one. It fills out on its own as guides land.

   Not cards. This sits directly above the disclaimer and a grid of boxes there
   turns the end of the page into furniture. */
.more-info{margin:40px 0 0; padding:30px 32px 32px;
  background:var(--pine-soft); border-radius:var(--radius);}
.more-info > h2{margin:0 0 22px; padding:0; font-size:22px; text-align:center;
  color:var(--head);}
.more-info > h2::before{content:none;}   /* no section rule inside a panel */
.mi-cols{display:grid; grid-template-columns:1fr 1fr; gap:28px 40px;}
.mi-cols h3{margin:0 0 12px; font-family:var(--mono); font-size:11px;
  letter-spacing:.13em; text-transform:uppercase; color:var(--rust);
  font-weight:600;}
.mi-cols ul{margin:0; padding:0; list-style:none;}
.mi-cols li{margin:0 0 11px; font-size:14.5px; line-height:1.5;
  color:var(--grey); text-wrap:pretty;}
.mi-cols li:last-child{margin-bottom:0;}
.mi-cols a{display:inline; color:var(--head); font-weight:600;
  text-decoration:none; border-bottom:1.5px solid var(--brass);}
.mi-cols a:hover{color:var(--rust); border-color:var(--rust);}
.mi-cols .note{display:block; margin-top:2px; font-size:13px; color:var(--grey);}

html[data-theme="dark"] .more-info{background:var(--paper-card);
  border:1.5px solid var(--line);}

@media (max-width:700px){
  /* One column. Two 40px-gapped columns inside a 720px measure are already
     tight; below this they become two narrow gutters of wrapped links. */
  .more-info{padding:24px 20px 26px;}
  .mi-cols{grid-template-columns:1fr; gap:24px;}
}

/* ---- SOURCES --------------------------------------------------------------
   Where the numbers came from, at the foot of the article, above the
   disclaimer. Two reasons it exists and only one of them is SEO.

   The honest one: these guides state figures that change — a rate, a
   threshold, a deadline. A reader who wants to check should not have to
   search, and a reader who reads this in eighteen months needs to know which
   year the numbers belong to and where to find the current ones.

   The other: primary sources are what separate a guide from content. Anyone
   can assert 15.3%. Linking the IRS page that says so, with the date it was
   last reviewed, is the part that is expensive to fake.

   Deliberately small and quiet. This is apparatus, not argument. */
.sources{margin:34px 0 0; padding:20px 0 0; border-top:1.5px solid var(--line);}
.sources h3{margin:0 0 12px; font-family:var(--mono); font-size:11px;
  letter-spacing:.13em; text-transform:uppercase; color:var(--grey);
  font-weight:600;}
.sources h3::before{content:none;}
.sources ol{margin:0; padding:0 0 0 20px;}
.sources li{margin:0 0 8px; font-size:13.5px; line-height:1.55;
  color:var(--grey); text-wrap:pretty;}
.sources li:last-child{margin-bottom:0;}
.sources a{color:var(--head); text-decoration:none;
  border-bottom:1px solid var(--brass);}
.sources a:hover{color:var(--rust); border-color:var(--rust);}
/* The retrieval date is the point of a citation to a page that changes. */
.sources .when{color:var(--grey); font-style:normal; white-space:nowrap;}

/* ---- FIGURES: charts ------------------------------------------------------
   Inline SVG, no charting library: it themes itself from the custom
   properties, the numbers stay real selectable text rather than a picture of
   information, and it weighs nothing.

   EVERY CLASS IN HERE IS PREFIXED ch-, and that is not tidiness.

   The first version used .bar, .val and .lbl. styles.css:1217 already defines
   .bar for the homepage's CSS bar chart — flex:1, position:relative,
   display:flex — and .val at :1246 as position:absolute. Those rules applied
   to the SVG <rect> elements, because a class selector does not care what
   element it lands on, and modern CSS lets width/height/display reach SVG
   geometry. The tall bars rendered several hundred pixels past the baseline,
   straight through the legend and the caption.

   Scoping to .chart .bar did not save it either: that wins the properties it
   declares and leaves every property it does not declare still applying.
   The only reliable fix is a namespace nothing else can collide with. */
.chart{margin:30px 0; padding:24px 26px 20px;
  background:var(--paper-card); border:1.5px solid var(--line);
  border-radius:var(--radius);}
/* Clip rather than spill. If a future edit ever gets the geometry wrong again,
   the chart should look cropped — obviously broken — instead of quietly
   drawing over the text underneath it. */
.chart svg{display:block; width:100%; height:auto; overflow:hidden;}
.chart figcaption{margin:16px 0 0; padding-top:14px;
  border-top:1px solid var(--line);
  font-size:13.5px; line-height:1.55; color:var(--grey); text-wrap:pretty;}
.chart .ch-title{margin:0 0 4px; font-size:15px; font-weight:600;
  color:var(--head); font-family:var(--sans);}
.chart .ch-sub{margin:0 0 18px; font-size:13px; color:var(--grey);}

.ch-lbl{font-family:var(--mono); font-size:10px; letter-spacing:.04em;
  fill:var(--grey);}
.ch-val{font-family:var(--mono); font-size:10px; font-weight:600;
  fill:var(--head);}
.ch-avgline{stroke:var(--rust); stroke-width:1.6; stroke-dasharray:5 4;
  fill:none;}
.ch-avglbl{font-family:var(--mono); font-size:10px; fill:var(--rust);
  font-weight:600; letter-spacing:.04em;}
.ch-base{stroke:var(--line); stroke-width:1;}
.ch-bar{fill:var(--brass);}
.ch-bar-under{fill:var(--brass); opacity:.42;}
.ch-se{fill:var(--rust);}
.ch-inc{fill:var(--brass);}
.ch-keep{fill:var(--pine);}
html[data-theme="dark"] .ch-keep{fill:#3E6B54;}

.ch-key{display:flex; flex-wrap:wrap; gap:8px 20px; margin:16px 0 0;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--grey);}
.ch-key span{display:inline-flex; align-items:center; gap:7px;}
.ch-key i{width:11px; height:11px; border-radius:3px; flex:none;}
@media (max-width:520px){
  .chart{padding:18px 16px 16px;}
}
