/* GENERATED by marketing/build-tool-partials.py — DO NOT EDIT.
   Source of truth: marketing/tools/tools-core/tools-core.css */
/* Two derived changes, both load-bearing ONLY when embedded:
   1. `:root` → `.ist-tool`, so the tool's tokens cannot be overridden by
      the theme's light-mode :root[data-theme] block.
   2. every `.ist-tool…` selector hardened to (0,3,0)+, so the theme's
      same-named generic classes (.lede, .muted, .verdict) cannot win. */
/* =============================================================================
 * Incomestead tools-core — the shared design system for the /tools suite.
 *
 * Warm Stone (dark) ground, because the suite is the app's freemium front door
 * and the tool should feel like the product you are being onboarded into
 * (architecture §2.3; Tools Spec §0 locks the theme — not an open decision).
 *
 * BRAND RULES — the same ones the app enforces. Source of truth:
 *   `Incomestead Branding pack/incomestead-brand-spec.md` (v1.0, locked) and
 *   `Incomestead/frontend/UI-STANDARDS.md` §1, §4, §5.
 *
 *  1. A brand colour is ALWAYS a token. Never a literal — not a hex in a rule,
 *     and NOT an rgb triplet inside rgba(). `rgba(210,163,86,.2)` IS   tools-brand-ok
 *     --accent-active at 20%, spelled out, and it silently stops tracking the
 *     token the day the bronze is retuned. Use:
 *         color-mix(in srgb, var(--tok) N%, transparent)
 *     Exempt: pure black/white scrims, and --edge (documented as intentionally
 *     outside the warm-stone family).
 *  2. Bronze is a SCALE, not a swatch. --accent RESTS (brand, structure, quiet
 *     marks); --accent-active is the ACTIVE signal ONLY — the live "decide"
 *     moment, the zone you are actually in. Green owns healthy, brick owns
 *     alarm, so bronze always means ENGAGE. Keep Lit Bronze scarce (CA7).
 *  3. Type: Spectral = display, sparingly · Hanken Grotesk = UI + wordmark ·
 *     IBM Plex Mono = ALL numbers, with tabular-nums.
 *  4. Spacing is the app's scale: --card-gap between cards, --pad-x/--row-y/
 *     --seam-y/--sp-* within them. A row's padding never depends on its
 *     children (UI-STANDARDS §1.3).
 *  5. No text on a bar (§4.3). The bar carries marks; the label goes above.
 *
 * Everything is scoped under `.ist-tool` so a tool can be embedded in a Ghost
 * page without colliding with the theme.
 * ========================================================================== */

.ist-tool.ist-tool.ist-tool.ist-tool {
  /* Palette — brand spec §2.1. THIS IS THE TOKEN DEFINITION SITE, the only
     place a hex may appear. Every rule below references a var(). */
  --bg: #1E1A16;              /* Warm Stone — ground */
  --surface: #26211B;         /* panels & cards */
  --raised: #352E25;          /* tracks, insets */
  --line: #463D31;            /* hairlines */
  --text: #F3F0E9;            /* Limestone */
  --muted: #A99E8E;           /* warm ink — secondary TEXT. Owner call 2026-07-27. */
  /* WHY THIS IS NOT PEWTER. The brand spec §2.1 assigns Pewter to "secondary
     text", but at that value it measures 3.63:1 on --surface and 3.04:1 on
     --raised — it fails WCAG AA (4.5:1) for normal text on every ground a tool
     paints, and it drove all thirteen secondary-text roles here. The app had
     already found this and worked around it with the warm-ink ramp in
     rooms.css (--ink-1..7, "secondary-text tints between --text and --muted"),
     but that fix was never written back into the spec, so this file re-created
     the original defect when it was authored from the spec.
     This value IS that ramp's --ink-7 ("dim — room sub-headers, captions"), so
     the app and the tools now teach one vocabulary. It measures 6.06 / 6.56 /
     5.08 on --surface / --bg / --raised: AA with headroom, which is the point —
     a dark island inside a LIGHT article is read by a light-adapted eye, and
     veiling glare from the bright surround eats contrast that the WCAG formula
     does not model. Cool and warm candidates were within 0.07 of each other on
     every ground; the choice was temperature, and warm won on coherence with
     the app. Follow-up: rooms.css still has ~110 rules on the old value. */
  --accent: #A6835A;          /* Provision Bronze — RESTS */
  --accent-active: #D2A356;   /* Lit Bronze — the live decide moment ONLY */
  --accent-deep: #7E6442;     /* bronze depth */
  --positive: #5FA98A;        /* Endowment Green — healthy / in-band */
  --positive-fill: #2E5A4C;
  --alarm: #C15A4E;           /* Brick — alarm only. NEVER a `color:` — as an ink it
                                 measures 3.08/3.68/3.98 on the three grounds, all under
                                 the 4.5 floor. Marks, borders and tints only (DS-63). */
  --alarm-ink: #DB8B80;       /* Brick as TEXT — 6.09 on --surface. Mirrors the app's
                                 token of the same name (styles.css); the tools had no
                                 alarm ink at all until DS-25 needed one, which is how a
                                 `var(--alarm-ink)` here would have silently resolved to
                                 EMPTY and inherited the surrounding colour instead. */
  --edge: #8a9aa0;            /* band-edge numerals; deliberately cool */

  /* THE ZONE SCALE — brand spec §2.1b, LOCKED 2026-08-02 (Q10b, closes DS-08).
     Identical to the app's styles.css block; the two are compared by
     .githooks/check-zone-bar.sh, which is what keeps this a port rather than a
     lookalike. FILLS ARE OPAQUE so the ratio belongs to the token and not to the
     ground — the only shape that can be ONE bar on a dark tool and a white blog
     page. ONE ink on all four steps. --zone-forced-fill is deliberately NOT
     --alarm-fill, which measures 2.95 under --zone-ink; see THE ALARM RULE's
     declared-scale clause in §2.1a. Do not retune here — change §2.1b, then every
     surface. (Values are annotated by RATIO, not by hex: the brand guard treats a
     hex outside a token definition as a literal, and it is right to — §2.1b is
     where the values are written down.) */
  --zone-clear-fill:   #599F82;              /* 5.52 on --zone-ink */
  --zone-harvest-fill: var(--accent);        /* 4.95 */
  --zone-freeze-fill:  var(--accent-active); /* 7.50 — §2.3's locked CTA pairing */
  --zone-forced-fill:  #D06154;              /* 4.54; top of the legal range is 4.96 */
  --zone-ink:          var(--bg);            /* all four steps */

  --font-display: "Spectral", Georgia, "Times New Roman", serif;
  --font-ui: "Hanken Grotesk", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;

  --r: 14px;                  /* card radius — matches the app's rooms */
  --r-control: 9px;           /* control radius — buttons, inputs, selects (DS-74).
                                  Matches the host theme's .nav-cta/.pg-link and the
                                  app's .enter (T-187 ruling 2026-08-05). */
  --r-pill: 999px;            /* fully-rounded — badges, stadium tracks (DS-74) */
  --card-gap: 14px;           /* card-to-card. Never hard-code a card gap. */
  --pad-x: 15px;              /* horizontal inset. Every row. No exceptions. */
  --row-y: 12px;              /* a row's own vertical breathing — THE DEFAULT */
  --seam-y: 8px;              /* where a row continues into the next */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;

  /* Named z-index scale (DS-36) — declared ahead of a live consumer, on purpose.
     The tools embed under the host theme's `header.site`, which is
     `position: sticky; z-index: 40`. Today no tool has a tooltip or popover
     (its 6 `position: absolute` rules are all in-track markers with nowhere to
     escape to), so nothing currently collides — but the app's three tooltip
     sites are the obvious model to copy into a tool next, and a copied
     component with no z-index guidance would silently render UNDER the
     scrolled header the first time. --z-overlay clears --z-sticky by design;
     reach for these instead of guessing a number. Matches the scale proposed
     in design-system/incomestead-design-system.md §P8 — do not invent a
     second set of tiers. */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 40;    /* parity with the host theme's header.site */
  --z-overlay: 60;   /* tooltips / popovers — clears --z-sticky */
  --z-modal: 80;

  color-scheme: dark;
}

.ist-tool.ist-tool.ist-tool.ist-tool {
  background: var(--bg);
  color: var(--text);
  font: 16px/1.55 var(--font-ui);
  letter-spacing: .004em;
  -webkit-font-smoothing: antialiased;
  max-width: 720px;
  margin: 0 auto;
  padding: var(--sp-4);
}
.ist-tool.ist-tool.ist-tool.ist-tool * { box-sizing: border-box; }

/* SCROLL ANCHORING OFF — the second half of cross-tool rule 8, and the half that
   is invisible without a real browser.

   Browsers watch for content above the viewport changing height and silently
   shift the scroll position to compensate, so a late-loading image doesn't shove
   the paragraph you are reading. Inside a tool that compensation is wrong by
   construction: a wizard step swap is a DELIBERATE height change, and the tool
   re-parks the reader itself via shell.js `anchor()`.

   Worse, the two RACE. Measured 2026-07-28 in the embedded-context harness:
   Charter step 1 → 2 grows the card by 449px, and the reader landed exactly
   449px BELOW the tool's top — the anchor computed the right target, then the
   browser's compensation overrode it. It only shows on the smooth path (the
   theme's `html { scroll-behavior: smooth }`): an instant scroll lands before
   the compensation is applied and resets the anchor node, which is why the
   reduced-motion path measured perfect while the default one was off by exactly
   one step's growth.

   `none` opts this element AND its subtree out of anchor-node selection, so the
   browser picks something outside the tool whose height is not changing, and the
   tool's own scroll position is the last word. Safari implements no scroll
   anchoring at all, so it was always correct there — another reason this needed a
   measurement rather than a reviewer.

   WHAT WE GIVE UP, stated rather than discovered later: with anchoring off, tool
   content that grows ABOVE the reader would shift their view instead of being
   compensated for. That is acceptable HERE and only here, because the tools
   already forbid the thing it protects against — UI-STANDARDS §3.2, which is why
   the Reality Check's verdict card is reserved and renders empty rather than
   popping in. The exclusion is scoped to the tool's subtree, so the article's own
   late-loading content keeps its anchoring. Guard: test/shell.test.js + the
   harness's scroll:anchoring-off check. */
.ist-tool.ist-tool.ist-tool.ist-tool { overflow-anchor: none; }

/* The `hidden` attribute must actually hide. Every tool drives its progressive
   disclosure through it, so this one rule is load-bearing for the whole suite.
   `!important` is required, not stylistic — TWO separate things defeat the plain
   user-agent `[hidden] { display: none }`:

   1. Cascade ORIGIN. Any author rule setting `display` beats the UA rule however
      specific the UA selector is. `#values-inputs` carries `class="two"`
      (margin-zone-checker.html:47) and `.ist-tool .two` sets `display: grid`
      below — so the Zone Checker's direct-entry toggle has been showing BOTH
      input groups at once, on the standalone host too. This rule fixes that.
   2. `all: revert` in the theme-bleed reset that the Ghost embed applies to
      every descendant (marketing/build-tool-partials.py) does NOT restore the UA
      rule: a `[hidden]` element inside a tool computed `block` where the same
      element outside computed `none`. Measured 2026-07-27 against the live page.

   It lives HERE, in the shared substrate, rather than in the embed glue, so the
   standalone host and the embedded post behave identically — that parity is the
   whole point of T-159. `:not([hidden="until-found"])` keeps find-in-page
   working if a tool ever adopts it; none does today. Nothing else in this file
   uses `!important`, so this shadows nothing. Guard: test/hidden.test.js. */
.ist-tool.ist-tool.ist-tool.ist-tool [hidden]:not([hidden="until-found"]) { display: none !important; }

/* ---- type ---------------------------------------------------------------- */
/* `.ist-tool-title` is the SAME title, one heading level down. A standalone tool
   owns its page and marks its title `<h1>`; the derived partial demotes it to
   `<h2 class="ist-tool-title">`, because inside a post the POST title is already
   the page's h1 (build-tool-partials.py, Tool.__init__). The class exists so the
   demotion is semantic only — it carries this typography across, and at (0,2,0)
   it beats `.ist-tool h2` (0,1,1) below, so the title keeps the display face
   instead of inheriting the section-heading UI face. Both halves start
   `.ist-tool`, so harden() lifts them together and the relationship survives the
   ×4 rewrite. */
.ist-tool.ist-tool.ist-tool.ist-tool h1,
.ist-tool.ist-tool.ist-tool.ist-tool .ist-tool-title { font: 400 27px/1.25 var(--font-display); margin: 0 0 var(--sp-2); }
/* THE PROSE LADDER — h2 18 / lede 17 / body 16 / kv 15 (+1 for the kv value).
   Moved as ONE unit 2026-08-02 (DS-45, owner-approved): the body went 15 -> 16, so
   every step tied to it went with it. Moving the base alone would have collided the
   lede with this heading at 17px — a regression a PARTIAL application invents.

   What did NOT move, and why: the eyebrow (11), the tool title (27), the verdict
   head (24) and the verdict numerals (13) are sized against the CARD, not against
   the prose. They are fixed roles, not rungs. Adding a rung? Put it here. */
.ist-tool.ist-tool.ist-tool.ist-tool h2 { font: 600 18px/1.3 var(--font-ui); margin: 0 0 var(--sp-2); }
.ist-tool.ist-tool.ist-tool.ist-tool p { margin: 0 0 var(--sp-3); }
.ist-tool.ist-tool.ist-tool.ist-tool .lede { color: var(--text); font-size: 17px; }
.ist-tool.ist-tool.ist-tool.ist-tool .muted { color: var(--muted); }
.ist-tool.ist-tool.ist-tool.ist-tool .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* The eyebrow — 11px, .22em tracking, uppercase, muted (UI-STANDARDS §5.3). */
.ist-tool.ist-tool.ist-tool.ist-tool .eyebrow {
  font: 600 11px/1.2 var(--font-ui);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--sp-2);
}

/* ---- cards --------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--row-y) var(--pad-x);
  margin-bottom: var(--card-gap);
}
.ist-tool.ist-tool.ist-tool.ist-tool .card > :last-child { margin-bottom: 0; }

/* The verdict card — the one place the tool answers the question. */
.ist-tool.ist-tool.ist-tool.ist-tool .verdict { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.ist-tool.ist-tool.ist-tool.ist-tool .verdict-good { border-color: color-mix(in srgb, var(--positive) 55%, transparent); }
.ist-tool.ist-tool.ist-tool.ist-tool .verdict-alarm { border-color: color-mix(in srgb, var(--alarm) 60%, transparent); }
.ist-tool.ist-tool.ist-tool.ist-tool .verdict-head {
  font: 400 24px/1.2 var(--font-display);
  margin: 0 0 var(--sp-1);
}
.ist-tool.ist-tool.ist-tool.ist-tool .verdict-num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--muted);
}

/* ---- pills — the three-state vocabulary ---------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .pill {
  display: inline-block;
  padding: 1px var(--sp-2);
  border-radius: 999px;
  font: 600 11px/1.7 var(--font-ui);
  letter-spacing: .04em;
  border: 1px solid;
}
.ist-tool.ist-tool.ist-tool.ist-tool .pill-ok {
  color: var(--positive);
  border-color: color-mix(in srgb, var(--positive) 55%, transparent);
  background: color-mix(in srgb, var(--positive) 12%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .pill-bronze {
  color: var(--accent-active);
  border-color: color-mix(in srgb, var(--accent-active) 55%, transparent);
  background: color-mix(in srgb, var(--accent-active) 12%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .pill-alarm {
  color: var(--alarm-ink);
  border-color: color-mix(in srgb, var(--alarm) 60%, transparent);
  background: color-mix(in srgb, var(--alarm) 12%, transparent);
}

/* ---- compact layout primitives -------------------------------------------
 * Ported from the marketing homepage, which is the density the owner wants:
 * `.two` puts related content side by side instead of stacking it, and `.kv`
 * states a fact in one 7px-padded row instead of a three-line block. A tool
 * that scrolls is a tool that gets abandoned before the verdict.
 * ------------------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-4); }

/* T-188 H4 — a table that cannot fit its column needs somewhere to go.
   Measured at 375px embedded with the Charter's `#doc` populated: its first
   4-column table lays out at 340.2px inside a 277px `.doc`, right edge 389.2px —
   14.2px past the viewport. `document.documentElement.scrollWidth` stays 375,
   because an ancestor clips it, so the predicted page-level horizontal scroll never
   appears and the overflow is SILENT: the rightmost column is simply unreachable,
   with no scrollbar and no tell. That is worse than the scroll it was expected to
   cause, not better.

   A shared primitive rather than a third private copy: the planner already solved
   this with its own `.ybwrap`, and the Charter and Reality Check each grew a table
   without one. Three names for one concept is exactly the disease T-188(d)
   diagnosed in `.two` — the kit teaching a pattern it does not follow.
   ⚠ `.ybwrap` is deliberately NOT folded in here; converging it is a separate diff
   against a surface that is currently correct and tested. */
.ist-tool.ist-tool.ist-tool.ist-tool .tbl-scroll { overflow-x: auto; }

/* The homepage's label:value row — the whole reason the verdict now fits on a
   screen. Border does the separating; no card, no gap, no sub-line. */
.ist-tool.ist-tool.ist-tool.ist-tool .kv {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3);
  padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 15px;
}
.ist-tool.ist-tool.ist-tool.ist-tool .kv:last-child { border-bottom: none; }
.ist-tool.ist-tool.ist-tool.ist-tool .kv .k { color: var(--muted); }
/* opacity .9, not .8 — alpha composites away contrast the token retune just
   bought. At .8 this 11px sub-label measured 4.40:1 on --surface (fails AA); at
   .9 it is 5.20:1 and still visibly quieter than the key above it. */
.ist-tool.ist-tool.ist-tool.ist-tool .kv .k small { display: block; font-size: 11px; opacity: .9; }
.ist-tool.ist-tool.ist-tool.ist-tool .kv .v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  white-space: nowrap; font-size: 16px;
}
.ist-tool.ist-tool.ist-tool.ist-tool .kv .v.pos { color: var(--positive); }
.ist-tool.ist-tool.ist-tool.ist-tool .kv .v.warn { color: var(--accent-active); }
.ist-tool.ist-tool.ist-tool.ist-tool .kv .v.crit { color: var(--alarm-ink); }

/* ---- links ----------------------------------------------------------------
 * EVERY anchor inside a tool, styled here and nowhere else.
 *
 * This is a `.ist-tool a` blanket rule, not a rule for the one class that
 * exists today (`.next-link`), and that is the whole point. Until 2026-07-30
 * this file had NO anchor rule of any kind: `.next-link` was emitted by
 * kit.js `nextCard()` and by three tools, and matched by nothing, so every
 * outbound step in the suite painted in the browser's default link colour —
 * measured on the live page as Chrome's dark-scheme `-webkit-link` periwinkle.
 * A cold blue-violet is the one hue the Warm Stone palette does not contain,
 * so it read as a foreign element on the card, and it went live that way.
 *
 * A class-scoped rule would have left the same hole open for the next anchor
 * anyone adds. The blanket rule closes the class of defect; a future link
 * variant opts OUT of it deliberately instead of silently never opting in.
 *
 * Colour is RESTING bronze (§5 — `--accent-active` is the live decide moment
 * only, and an onward link is not one). 4.95:1 on --bg and 4.57:1 on --surface:
 * AA for normal text on both grounds a tool paints. Hover lifts to Lit Bronze,
 * matching `.linkish` below so the two text affordances behave alike. The
 * underline is not decoration — it is the non-colour cue (WCAG 1.4.1), so it
 * stays in every state.
 * ------------------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--accent) 55%, transparent);
  transition: color .15s ease, text-decoration-color .15s ease;
}
.ist-tool.ist-tool.ist-tool.ist-tool a:hover,
.ist-tool.ist-tool.ist-tool.ist-tool a:focus-visible {
  color: var(--accent-active);
  text-decoration-color: var(--accent-active);
}
/* `:visited` is pinned to the same bronze on purpose. The UA default repaints a
   visited link purple, which would reintroduce exactly the foreign hue this
   rule exists to remove — on the second visit only, i.e. the one a reviewer is
   least likely to be looking at. */
.ist-tool.ist-tool.ist-tool.ist-tool a:visited { color: var(--accent); }
.ist-tool.ist-tool.ist-tool.ist-tool a:visited:hover { color: var(--accent-active); }

/* The onward step out of a tool. Reads as a deliberate next action rather than
   a reference, so it carries the tool's UI face and a little more weight than
   surrounding prose. */
.ist-tool.ist-tool.ist-tool.ist-tool .next-link { font-weight: 600; }

/* A quiet text button for a secondary path ("…or enter it directly"). */
.ist-tool.ist-tool.ist-tool.ist-tool .linkish {
  background: none; border: none; padding: 0; font: inherit; font-size: 12px;
  color: var(--muted); text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.ist-tool.ist-tool.ist-tool.ist-tool .linkish:hover { color: var(--accent-active); }

/* Collapsed helper — the broker-by-broker guidance is essential for the one
   visitor who needs it and pure noise for the nine who do not. */
.ist-tool.ist-tool.ist-tool.ist-tool details.helper { margin-top: var(--seam-y); }
.ist-tool.ist-tool.ist-tool.ist-tool details.helper > summary {
  cursor: pointer; font-size: 12px; color: var(--muted); list-style: none;
}
.ist-tool.ist-tool.ist-tool.ist-tool details.helper > summary::-webkit-details-marker { display: none; }
.ist-tool.ist-tool.ist-tool.ist-tool details.helper > summary::before { content: "+ "; color: var(--accent); }
.ist-tool.ist-tool.ist-tool.ist-tool details.helper[open] > summary::before { content: "– "; }
.ist-tool.ist-tool.ist-tool.ist-tool details.helper .hbody {
  font-size: 12px; color: var(--muted); line-height: 1.6;
  padding: var(--seam-y) 0 0; margin: 0;
}
.ist-tool.ist-tool.ist-tool.ist-tool details.helper .hbody li { margin-bottom: 3px; }
.ist-tool.ist-tool.ist-tool.ist-tool details.helper .hbody b { color: var(--text); font-weight: 600; }

/* THE DENOMINATOR, stated on screen (T-172). One rule, rendered anywhere the
   suite asks for or reports a utilisation, so four surfaces cannot drift into
   four denominators. Text comes from `ui.zones.definition` — never hand-written
   at the call site.

   Bronze at REST for the left rule (`--accent`, 4.17:1 — clears the 3:1
   non-text floor), deliberately NOT `--accent-active`: this is a standing
   definition, not an active signal, and Lit Bronze is scarce by BRAND RULE 2 /
   CA7. `--muted` for the body measures 5.08–6.56:1 across the three grounds.
   Not `--accent-deep`, which fails at 2.62:1 (T-183). */
.ist-tool.ist-tool.ist-tool.ist-tool .zone-def {
  font-size: 12px; line-height: 1.6; color: var(--muted);
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px var(--sp-3); margin: var(--seam-y) 0 0;
}
.ist-tool.ist-tool.ist-tool.ist-tool .zone-def b { color: var(--text); font-weight: 600; }
/* Empty until the config resolves — hold no space rather than reserve a gap the
   reader reads as a layout bug on a slow params fetch. */
.ist-tool.ist-tool.ist-tool.ist-tool .zone-def:empty { display: none; }

/* ---- the contextual consent affordance (T-175 Option B) -------------------
 * Deliberately the SAME grammar as .zone-def above — 2px resting bronze, no
 * fill, no frame — and for the same reason: it states what is true of the
 * reading that has just appeared. It is not an alarm and not a call to action,
 * so it borrows an established meaning rather than inventing a third one. Owner
 * choice 2026-08-01, from three candidates rendered at real size on this ground.
 *
 * `--muted` on the state line and `--text` on the label: the label is the part
 * the reader acts on, so it gets the higher-contrast ink. Both clear AA on
 * --surface (the verdict card), which is the only ground this renders on.
 *
 * Empty until the shell fills it, and holding no space until then — a reserved
 * gap under a fresh reading reads as a layout bug (UI-STANDARDS §3.2). */
.ist-tool.ist-tool.ist-tool.ist-tool .persist-offer {
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px var(--sp-3);
  margin: var(--row-y) 0 0;
}
.ist-tool.ist-tool.ist-tool.ist-tool .persist-offer:empty { display: none; }
.ist-tool.ist-tool.ist-tool.ist-tool .persist-offer .po-state {
  margin: 0 0 var(--sp-2); font-size: 13px; line-height: 1.55; color: var(--muted);
}
.ist-tool.ist-tool.ist-tool.ist-tool .persist-offer label {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  color: var(--text); cursor: pointer; font-size: 13px; line-height: 1.45;
}
.ist-tool.ist-tool.ist-tool.ist-tool .persist-offer input {
  accent-color: var(--accent); cursor: pointer; margin-top: 2px; flex: none;
}

/* An input guard — fires on a value that is probably the wrong field, not on a
   value that is merely bad news. */
.ist-tool.ist-tool.ist-tool.ist-tool .guardnote {
  font-size: 12px; line-height: 1.5; color: var(--accent-active);
  border-left: 2px solid var(--accent-active);
  padding: 2px 0 2px var(--sp-3); margin-top: var(--seam-y);
}

/* ---- report blocks (the gated detail) -------------------------------------
 * A zone callout, a numbered step list, and an accented aside for the rule the
 * whole thing turns on. Shared so every tool's "what this means" reads the same.
 * ------------------------------------------------------------------------- */

/* The zone callout — a lead statement with a tone-keyed left accent, so the
   meaning of the reading carries the reading's colour (green calm / bronze
   attention / brick alarm) rather than arriving as undifferentiated prose. */
.ist-tool.ist-tool.ist-tool.ist-tool .zone-callout {
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
  border-radius: 0 var(--r) var(--r) 0;   /* DS-74(b): was 0 8px 8px 0, owner-approved fold into --r */
  padding: var(--row-y) var(--pad-x);
  margin: 0 0 var(--card-gap);
}
.ist-tool.ist-tool.ist-tool.ist-tool .zone-callout.tone-ok {
  border-left-color: var(--positive);
  background: color-mix(in srgb, var(--positive) 7%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .zone-callout.tone-warn {
  border-left-color: var(--accent-active);
  background: color-mix(in srgb, var(--accent-active) 7%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .zone-callout.tone-crit {
  border-left-color: var(--alarm);
  background: color-mix(in srgb, var(--alarm) 7%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .zc-lead {
  font-family: var(--font-display); font-size: 17px; line-height: 1.4;
  margin: 0 0 var(--sp-2);
}
.ist-tool.ist-tool.ist-tool.ist-tool .zc-lead strong { color: var(--text); }
.ist-tool.ist-tool.ist-tool.ist-tool .zc-body {
  font-size: 14px; line-height: 1.55; margin: 0;
  color: color-mix(in srgb, var(--text) 80%, transparent);
}

/* Numbered checklist — a mono badge per step, dividers instead of bullets, so it
   reads as a procedure rather than a paragraph that happens to be a list. */
.ist-tool.ist-tool.ist-tool.ist-tool .steps-check { list-style: none; margin: 0; padding: 0; }
.ist-tool.ist-tool.ist-tool.ist-tool .steps-check li {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--row-y) 0; border-top: 1px solid var(--line);
}
.ist-tool.ist-tool.ist-tool.ist-tool .steps-check li:first-child { border-top: none; padding-top: var(--sp-2); }
.ist-tool.ist-tool.ist-tool.ist-tool .sc-n {
  flex: none; width: 22px; height: 22px; margin-top: 1px;
  display: grid; place-items: center; border-radius: 999px;
  font: 600 11px/1 var(--font-mono); color: var(--accent-active);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .sc-t { font-size: 14px; line-height: 1.55; }

/* The rule aside — the two-week persistence rule is the whole brand thesis
   ("governance, not a single number"), so it gets a framed, eyebrowed box, not
   a gray footnote. */
.ist-tool.ist-tool.ist-tool.ist-tool .rule-note {
  margin-top: var(--card-gap); padding: var(--row-y) var(--pad-x);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--r);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .rule-note .eyebrow { margin-bottom: var(--sp-1); }
.ist-tool.ist-tool.ist-tool.ist-tool .rule-note p:last-child {
  margin: 0; font-size: 13px; line-height: 1.55;
  color: color-mix(in srgb, var(--text) 82%, transparent);
}
.ist-tool.ist-tool.ist-tool.ist-tool .rule-note b { color: var(--accent-active); font-weight: 600; }

/* ---- inputs -------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .field { margin-bottom: var(--row-y); }
.ist-tool.ist-tool.ist-tool.ist-tool .two .field { margin-bottom: 0; }
.ist-tool.ist-tool.ist-tool.ist-tool .field label {
  display: block;
  font-size: 13px;
  color: var(--muted);
  margin-bottom: var(--sp-1);
}
.ist-tool.ist-tool.ist-tool.ist-tool input[type="text"],
.ist-tool.ist-tool.ist-tool.ist-tool input[type="number"],
.ist-tool.ist-tool.ist-tool.ist-tool input[type="email"],
.ist-tool.ist-tool.ist-tool.ist-tool input[type="date"],
.ist-tool.ist-tool.ist-tool.ist-tool textarea {
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: var(--sp-2) var(--sp-3);
  font: 16px/1.4 var(--font-mono);
  font-variant-numeric: tabular-nums;
  -webkit-appearance: none;   /* drop iOS/Safari inset chrome on the field */
  appearance: none;
}
.ist-tool.ist-tool.ist-tool.ist-tool textarea { font-family: var(--font-ui); font-variant-numeric: normal; }
/* An email is prose, not a figure — read it in the UI face, not tabular mono. */
.ist-tool.ist-tool.ist-tool.ist-tool input[type="email"] { font-family: var(--font-ui); font-variant-numeric: normal; }

/* Half-width field — an email or a short code does not need the whole card.
   min-width keeps it usable when the card itself is narrow (mobile), where 50%
   would be too tight to read an address in. */
.ist-tool.ist-tool.ist-tool.ist-tool input.half { width: 50%; min-width: 15rem; max-width: 100%; }
.ist-tool.ist-tool.ist-tool.ist-tool input::placeholder,
/* 85%, not 75% — the mix composites against the input's own --bg, so alpha eats
   the retune. Measured over --bg: 75% = 4.27:1 (fails AA), 85% = 5.09:1. The
   placeholder is still ~3x quieter than a typed value (--text is 15.2:1), so the
   "is this filled in?" distinction is unharmed. This was the worst text in the
   file before the retune, at 2.78:1 — below even the large-text floor. */
.ist-tool.ist-tool.ist-tool.ist-tool textarea::placeholder { color: color-mix(in srgb, var(--muted) 85%, transparent); }

.ist-tool.ist-tool.ist-tool.ist-tool input:focus-visible,
.ist-tool.ist-tool.ist-tool.ist-tool textarea:focus-visible,
.ist-tool.ist-tool.ist-tool.ist-tool select:focus-visible,
.ist-tool.ist-tool.ist-tool.ist-tool button:focus-visible {
  outline: 2px solid var(--accent-active);
  outline-offset: 2px;
}
.ist-tool.ist-tool.ist-tool.ist-tool input:focus { border-color: color-mix(in srgb, var(--accent-active) 70%, transparent); }

/* The browser paints a half-typed email as :invalid — an alarm the moment you
   type "s". Errors belong AFTER the attempt, not during it: the tool marks the
   field once it has been blurred. `.touched` is written by shell.js
   bindFieldValidity(), which shell.mount() calls — DS-25. For its whole life
   before that this class had ZERO writers, so suppressing :invalid below turned
   the native signal off and put nothing back: an invalid field showed NOTHING.
   If you are about to delete the JS, delete the suppression in the same edit. */
.ist-tool.ist-tool.ist-tool.ist-tool input:invalid { box-shadow: none; }

/* Solid --alarm, NOT the 70% mix this rule used to carry. A
   `color-mix(…, transparent)` composites against whatever it lands on, and over
   the input's own --bg that one resolved to 2.60:1 — under the 3:1 non-text
   floor (WCAG 1.4.11). Solid is 3.98. The alpha was never the lever; see the
   same lesson in the post register's _TINT_GROUNDS. */
.ist-tool.ist-tool.ist-tool.ist-tool input.touched:invalid,
.ist-tool.ist-tool.ist-tool.ist-tool textarea.touched:invalid,
.ist-tool.ist-tool.ist-tool.ist-tool select.touched:invalid { border-color: var(--alarm); }

/* The border is one channel and colour alone fails 1.4.1, so every invalid field
   also gets words. --alarm-ink, not --alarm: this is small TEXT (3.68 on the card
   would fail), and the ink token exists for exactly this (6.09). */
.ist-tool.ist-tool.ist-tool.ist-tool .field-err {
  margin: var(--sp-1) 0 0;
  font: 13px/1.45 var(--font-ui);
  color: var(--alarm-ink);
}
.ist-tool.ist-tool.ist-tool.ist-tool .field-err[hidden] { display: none; }

/* A native <select> on a dark ground renders as an OS-chrome light widget. Take
   the chrome off and draw our own caret so it reads as part of the instrument. */
.ist-tool.ist-tool.ist-tool.ist-tool select {
  -webkit-appearance: none; appearance: none;
  /* Size to the widest option + caret, not the whole line — a four-word zone
     picker across the full width reads as a waste. Never wider than its line. */
  width: auto;
  max-width: 100%;
  background-color: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-3);
  font: 16px/1.4 var(--font-ui);
  cursor: pointer;
  /* caret drawn with two gradients — no image, no external asset, no CDN */
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 15px top 55%, right 10px top 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.ist-tool.ist-tool.ist-tool.ist-tool select:hover { border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
/* The dropdown list itself is OS-drawn; this is the one hook browsers honour. */
.ist-tool.ist-tool.ist-tool.ist-tool select option { background: var(--surface); color: var(--text); }

.ist-tool.ist-tool.ist-tool.ist-tool button {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
  border-radius: var(--r-control);   /* §2.3 control radius — matches the host theme's .nav-cta/.pg-link and the app's .enter (T-187 ruling 2026-08-05). Tokenised at DS-74. */
  padding: var(--sp-2) var(--sp-4);
  font: 600 14px/1.4 var(--font-ui);
  cursor: pointer;
}
/* Lit Bronze is the LIVE decide moment only — keep it scarce (CA7). */
.ist-tool.ist-tool.ist-tool.ist-tool button.primary {
  background: color-mix(in srgb, var(--accent-active) 22%, transparent);
  border-color: var(--accent-active);
  color: var(--text);
}
.ist-tool.ist-tool.ist-tool.ist-tool button[disabled] { opacity: .45; cursor: not-allowed; }

/* ---- the margin level bar -------------------------------------------------
 * Ported VERBATIM from the app's Standing room (`rooms.css` .level.tall /
 * .level-track / .seg / .marker / .level-foot, rendered by StandingRoom.tsx).
 * A visitor who converts must meet the same instrument twice — so the hues,
 * the 34px height, the labels inside each segment, the marker and the foot row
 * are the app's, not a lookalike.
 *
 * ⚠ THE ESCALATING TINTS ARE GONE — brand spec §2.1b (Q10b, LOCKED 2026-08-02,
 * closes DS-08). This comment used to say the escalation (positive 50 / accent 42
 * / accent-active 85 / alarm 85) WAS the grammar and must never be flattened.
 * That was right about the intent and wrong about the mechanism: a
 * color-mix(..., transparent) composites against its ground, so its ratio belongs
 * to the SURFACE, not the token. The escalation therefore measured differently on
 * every surface it was "ported verbatim" to — and the labels failed AA here and in
 * the app alike, at 2.52 on Freeze and 4.17 on Forced.
 *
 * The signal survives; it is now carried by four OPAQUE fills under ONE ink
 * (--zone-ink), which is the only shape that can be the same bar on a dark app and
 * a white blog page. Do not retune here — change §2.1b, then every surface, and
 * let .githooks/check-zone-bar.sh prove they agree.
 * ------------------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .level { position: relative; margin: 24px 4px 6px; }
/* `background: var(--bg)` is what the 2px gaps SHOW. The separator is mandatory,
 * not styling: CLEAR|HARVEST fill-vs-fill is 1.11 — near-equiluminant across a hue
 * change — so a hard edge shimmers and SC 1.4.11 is not met. Segments keep their
 * inline `width: %` and shrink proportionally to absorb the 6px, so 3fr 1fr 1fr 1fr
 * holds and markerFrac() stays honest to within 1px at every boundary. */
.ist-tool.ist-tool.ist-tool.ist-tool .level-track {
  display: flex; gap: 2px; background: var(--bg);
  height: 14px; border-radius: var(--r-pill); overflow: hidden; /* clamps to 7px at this height — same pixels as the literal it replaces (DS-74) */
  border: 1px solid var(--line);
}
.ist-tool.ist-tool.ist-tool.ist-tool .seg { height: 100%; }
.ist-tool.ist-tool.ist-tool.ist-tool .seg.clear   { background: var(--zone-clear-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .seg.harvest { background: var(--zone-harvest-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .seg.freeze  { background: var(--zone-freeze-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .seg.forced  { background: var(--zone-forced-fill); }

.ist-tool.ist-tool.ist-tool.ist-tool .level.tall .level-track { height: 34px; border-radius: 8px; }
/* `overflow: hidden` belongs on the SEGMENT, not only on the label inside it —
   corrected 2026-08-09, and the note on `.seg span` below was describing this
   mechanism while sitting one level too deep to trigger it. `min-width: auto` is a
   property of the FLEX ITEM, which here is `.seg`; the span is a flex item of `.seg`,
   not of the track, so zeroing ITS minimum leaves `.seg`'s own min-content
   contribution as the full label text and the segment keeps widening.
   The ≤480px rule hides the labels entirely, which is why this went unseen: it only
   bites at a viewport ABOVE 480px with a narrow container (a tool in a two-column
   post, a narrow card), and every earlier measurement was taken at a phone width
   where the labels were already gone. Measured at a 1280px viewport: without this,
   Clear lost 0.6px at a 312px track and 3.0px at 252px, which moves the seams and
   takes the boundary ticks off them; with it, ≤0.02px down to 204px. */
.ist-tool.ist-tool.ist-tool.ist-tool .level.tall .seg { display: flex; align-items: center; justify-content: center; overflow: hidden; }
.ist-tool.ist-tool.ist-tool.ist-tool .level.tall .seg span {
  font-size: 10px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  /* ONE ink on all four steps — §2.1b. 5.52 / 4.95 / 7.50 / 4.54. */
  color: var(--zone-ink);
  white-space: nowrap; overflow: hidden;
  /* T-188(c) — `overflow: hidden` here is load-bearing TWICE, and the second job is
     not obvious: a flex item whose overflow is not `visible` resolves `min-width:
     auto` to 0 rather than min-content, so the span shrinks below its own text
     instead of widening the segment. Do not "simplify" it away.
     `ellipsis` is the tell. Without it `text-overflow` defaults to `clip`, which
     cuts mid-glyph with no visual signal — measured at 375px, HARVEST rendered as
     a shorter word rather than as truncation, which is a different and worse defect
     class than a visible cut. Keep it even though the ≤480px rule below now removes
     these labels from the bar entirely: this is the backstop for every width BETWEEN
     481px and the desktop, which nobody has measured, and for the standalone pages,
     which load no webfont and fall back to a wider system-ui. */
  text-overflow: ellipsis;
}

/* T-188(c) — the phone legend. Emitted by kit.js zoneGauge on every surface that
   renders the gauge, but DISPLAY:NONE here and switched on only at ≤480px, where
   the in-segment labels are switched off. The bar is LOCKED as one standard
   (Q10b/DS-08), so above the breakpoint this row does not exist as far as the
   rendering is concerned.
   10px is rung 10 — on the DS-35 scale, which is the whole reason the labels moved
   out here rather than shrinking in place. */
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend {
  display: none;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-2);
}
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted);
}
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-sw {
  width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto;
}
/* The swatch is the ONLY carrier of the zone identity here, so it reuses the very
   same four fill tokens the segments use — not near-copies. A legend whose swatch
   drifts from its bar is a legend that lies. */
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-sw.clear   { background: var(--zone-clear-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-sw.harvest { background: var(--zone-harvest-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-sw.freeze  { background: var(--zone-freeze-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .level-legend .lg-sw.forced  { background: var(--zone-forced-fill); }
.ist-tool.ist-tool.ist-tool.ist-tool .marker {
  position: absolute; top: -9px; width: 3px; height: 32px; background: var(--text);
  border-radius: 2px; box-shadow: 0 0 0 3px color-mix(in srgb, var(--bg) 90%, transparent);
  transform: translateX(-50%);
}
.ist-tool.ist-tool.ist-tool.ist-tool .marker::after {
  content: ""; position: absolute; left: 50%; top: -6px;
  transform: translateX(-50%) rotate(45deg); width: 7px; height: 7px; background: var(--text);
}
.ist-tool.ist-tool.ist-tool.ist-tool .level.tall .marker { top: -4px; height: 42px; }

/* Boundary ticks, each absolutely positioned at its true fraction of the
   (non-linear) bar. Not a flex row of endpoints — the numbers must land under
   the seams they name, and on a magnified axis those seams are not evenly
   spaced. */
.ist-tool.ist-tool.ist-tool.ist-tool .level-ticks { position: relative; height: 13px; margin-top: 9px; }
.ist-tool.ist-tool.ist-tool.ist-tool .level-ticks .tick {
  position: absolute; top: 0; white-space: nowrap;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  /* line-height is PINNED to the row height, and that is load-bearing rather
     than tidy. Left to inherit, these labels take `.ist-tool`'s 1.55 and render
     a 15.5px line box inside a 13px row — so the row's declared height stops
     describing what is actually painted, and any vertical arithmetic done
     against it is quietly 2.5px wrong. That is exactly how the first fix for
     the off-scale collision landed 0.5px short and still overlapped: the
     numbers were right about the box and wrong about the text. */
  font-size: 10px; line-height: 13px; color: var(--muted);
}

/* THE OFF-SCALE READ GETS ITS OWN LINE — the one structural rule that makes a
   collision impossible rather than merely unlikely.

   Every label in this row is absolutely positioned, so nothing reflows out of
   another's way: two spans that intersect simply paint on top of each other.
   The boundary ticks can never collide with each other (they sit at 0 / 50 /
   66.7 / 83.3% and are ~20px wide), but the off-scale label is right-aligned
   and ~105–120px long, and the freeze_max tick is centred at 83.3% — so they
   contend for the same strip of the row. At the 680px column a tool gets inside
   a post that is a 0.8px gap for a two-digit reading and a 5.3px OVERLAP for a
   three-digit one. It shipped as an overlap.

   Widening the gap (smaller type, shorter wording, nudging the tick) only moves
   the threshold; the two labels still share one line box and some viewport
   still breaks it. A separate line removes the contention entirely, which is
   why this is a `top`, not a margin. Guarded: bar-geometry.test.js pins these
   three numbers, and the embed harness measures the rendered row for overlap. */
.ist-tool.ist-tool.ist-tool.ist-tool .level-ticks.has-off { height: 28px; }
.ist-tool.ist-tool.ist-tool.ist-tool .level-ticks .tick-off { top: 15px; color: var(--accent-active); }

/* Broken-axis disclosure — the bar is a deliberate zoom (Clear owns half, the
   action zones are magnified), so it says so rather than implying a linear
   scale (UI-STANDARDS §9 CA6). */
.ist-tool.ist-tool.ist-tool.ist-tool .gauge-note { font-size: 10px; line-height: 1.45; color: var(--muted); margin: 10px 0 0; }

/* An off-window reading dims its marker so the pinned position never reads as
   an exact one (the real figure is stated in the tick row and the hero). */
.ist-tool.ist-tool.ist-tool.ist-tool .marker.off { opacity: .55; }

/* The hero read — the app's Standing header: big mono figure + zone chip. */
.ist-tool.ist-tool.ist-tool.ist-tool .hero-read { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.ist-tool.ist-tool.ist-tool.ist-tool .hero-read .pct {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 38px; font-weight: 600; letter-spacing: -.01em;
}
.ist-tool.ist-tool.ist-tool.ist-tool .hero-read .zone {
  font-size: 11px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--bg); background: var(--accent-active); padding: 5px 11px; border-radius: 6px;
}
.ist-tool.ist-tool.ist-tool.ist-tool .hero-read .zone.ok { background: var(--positive); }
.ist-tool.ist-tool.ist-tool.ist-tool .hero-read .zone.crit { background: var(--alarm-fill); color: #fff; } /* tools-brand-ok */
.ist-tool.ist-tool.ist-tool.ist-tool .lab { font-size: 12px; color: var(--muted); font-weight: 500; }

/* ---- the band bar (Holdings policy-band grammar, copied verbatim) --------- */
.ist-tool.ist-tool.ist-tool.ist-tool .band-track {
  position: relative;
  height: 9px;
  border-radius: 5px;
  background: var(--bg);
  border: 1px solid var(--line);
  overflow: hidden;
}
/* THE POLICY BAND — copied VERBATIM from the app's `.ist .band-zone`, and the
   copy is now pinned by bar-geometry.test.js (DS-14).

   It used to be `--positive` at 26% with no edges, and that was not a tint
   drift: it was a GRAMMAR INVERSION. In the app, the bronze zone is where
   policy says the Layer belongs and GREEN is reserved for "your actual value
   is in band" (`.band-fill`, and `.cur-ok` on the marker right beside this
   track). Painting the TARGET green meant the same colour carried opposite
   meanings on two surfaces a reader moves between. The missing PAIRS entry is
   what let it sit there. */
.ist-tool.ist-tool.ist-tool.ist-tool .band-track .band {
  position: absolute;
  top: 0;
  bottom: 0;
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  border-left: 1px solid var(--accent-deep);
  border-right: 1px solid var(--accent-deep);
}
/* "You are here" — 3px bar + 6px diamond. THE shared marker. Copy verbatim.
   Verbatim means verbatim: the app (rooms.css `.ist .bandbar .cur`) puts the
   diamond ABOVE the bar (`top:-5px`), centres the mark with
   `transform: translateX(-50%)`, and lets the diamond take `background: inherit`
   so it can never drift from the bar it belongs to. The first cut of this file
   flipped the diamond to `bottom:-3px` — pointing DOWN, the opposite way round
   from every bar in the product — and duplicated the colour on both halves.
   Both are fixed here rather than overridden per tool.

   The padding reserves the diamond's clearance INSIDE the bar's own box, so the
   mark never overhangs into the label above it (UI-STANDARDS §1.4: clearance is
   reserved, not borrowed from a neighbour). Geometry: track at 18-29px, marker
   10-36px, so the two share a centre at ~23px and the diamond sits at 5-11px. */
.ist-tool.ist-tool.ist-tool.ist-tool .bandbar { position: relative; padding: 18px 0 10px; }
.ist-tool.ist-tool.ist-tool.ist-tool .bandbar .cur {
  position: absolute;
  top: 10px;
  width: 3px;
  height: 26px;
  border-radius: 2px;
  transform: translateX(-50%);
  background: var(--accent-active);
}
.ist-tool.ist-tool.ist-tool.ist-tool .bandbar .cur::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -5px;
  transform: translateX(-50%) rotate(45deg);
  width: 6px;
  height: 6px;
  background: inherit;
}
.ist-tool.ist-tool.ist-tool.ist-tool .bandbar .cur-ok { background: var(--positive); }
.ist-tool.ist-tool.ist-tool.ist-tool .bandbar .cur-alarm { background: var(--alarm); }
/* Edge numerals — cool grey, deliberately outside the warm-stone family. */
.ist-tool.ist-tool.ist-tool.ist-tool .edge {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10px;
  color: var(--edge);
}
.ist-tool.ist-tool.ist-tool.ist-tool .edges { display: flex; justify-content: space-between; margin-top: var(--sp-1); }

/* ---- the step rail ------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .rail {
  display: flex;
  gap: var(--sp-2);
  list-style: none;
  margin: 0 0 var(--card-gap);
  padding: 0;
  flex-wrap: wrap;
}
.ist-tool.ist-tool.ist-tool.ist-tool .rail li {
  font: 600 11px/1.2 var(--font-ui);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  padding: var(--sp-1) var(--sp-2);
  border-bottom: 2px solid var(--line);
}
.ist-tool.ist-tool.ist-tool.ist-tool .rail li[aria-current="step"] { color: var(--text); border-bottom-color: var(--accent-active); }
.ist-tool.ist-tool.ist-tool.ist-tool .rail li.done { color: var(--text); border-bottom-color: var(--accent); }

/* ---- the sum-to-100 validator -------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .sum {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--seam-y) var(--pad-x);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
}
.ist-tool.ist-tool.ist-tool.ist-tool .sum-ok { color: var(--positive); }
.ist-tool.ist-tool.ist-tool.ist-tool .sum-off { color: var(--accent-active); }

/* ---- footer: the promise + the privacy line ------------------------------ */
/* T-160 — the persistence consent control. Sits at the TOP of the footer, above
   the privacy line it qualifies, so the reader meets the choice and the claim
   together. Quiet by construction: this is a preference, not a call to action. */
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .persist { margin: 0 0 var(--row-y); }
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .persist label {
  display: flex; align-items: center; gap: var(--sp-2);
  color: var(--text); cursor: pointer;
}
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .persist input { accent-color: var(--accent); cursor: pointer; }
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .persist small { display: block; margin-top: var(--sp-1); }

/* T-114 — the Clear control, directly beneath the consent checkbox it belongs
   with: both describe what is STORED on the device. Quiet like the checkbox —
   this is a reassurance, not a call to action, so it stays a `.linkish` button
   rather than anything that competes with the tool's own primary action. The
   note sits inline so the outcome appears where the reader just clicked. */
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .clear-data { margin: 0 0 var(--row-y); }
.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot .clear-data small { margin-left: var(--sp-2); }

.ist-tool.ist-tool.ist-tool.ist-tool .toolfoot {
  border-top: 1px solid var(--line);
  padding-top: var(--row-y);
  margin-top: var(--card-gap);
  font-size: 12px;
  color: var(--muted);
}
/* The promise is TWO colours, and which half gets the bronze is not arbitrary.
   Public surfaces (homepage `.covenant`, the Ghost theme, the subscribe CTA)
   bold "You decide." in Lit Bronze — because the brand spec assigns the word
   "decide" to --accent-active by name, and bronze always means ENGAGE. The app
   chrome (rail, login gate) uses the OPPOSITE split, bolding "recommends." in
   resting bronze. A tool is a public marketing surface, so it takes the public
   split. Spectral, and NOT italic — the italic belongs to the app-chrome
   variant only. Ref: incomestead-brand-spec.md §2.2 + marketing/incomestead-
   homepage.html .covenant. */
.ist-tool.ist-tool.ist-tool.ist-tool .promise {
  color: var(--text);
  font-family: var(--font-display);
  font-size: 15px;
}
.ist-tool.ist-tool.ist-tool.ist-tool .promise b { color: var(--accent-active); font-weight: 700; }

/* ---- the subscribe slot ---------------------------------------------------
 * Ghost-native, 2026-08-18. Everything that used to live here was about a
 * CROSS-ORIGIN iframe: naming the frame's own background and colour-scheme so the
 * browser's default LIGHT canvas did not paint a white slab across a Warm Stone
 * card, and forcing border-radius:0 because a radius bit a quarter-disc out of the
 * embedded field instead of rounding the frame. There is no iframe now, so all of
 * it is deleted rather than ported (TOOLS-CORE-CONTRACT.md §8, amended).
 *
 * The form itself is styled by the THEME (`.ms-*` in default.hbs), not here, and
 * that is deliberate: on a Ghost post the theme stylesheet is present and its
 * tokens resolve against `.ist-tool`, so the control already matches the tool's
 * card. Duplicating those rules here would be a second copy to drift.
 *
 * Two things ARE ours, because they are about the tool's card rather than the
 * control:
 *   1. suppressing the theme's band, so the block does not paint a card inside a
 *      card — the same treatment `.capture .subscribe-cta` gets on the homepage;
 *   2. the standalone fallback, which the theme never sees.
 * ------------------------------------------------------------------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .subscribe-cta {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  max-width: none;
  text-align: left;
}

/* The STANDALONE fallback — a link, not a form. It renders only off-Ghost, where
 * Portal is absent and a form would have no submit handler; the theme build
 * replaces this element with the real form. See the IST-SIGNUP-FORM markers in
 * marketing/tools/*.html and the substitution in marketing/build-tool-partials.py. */
.ist-tool.ist-tool.ist-tool.ist-tool .ist-signup-offsite {
  font-size: 15px;
  line-height: 1.6;
}

/* ---- height stability: reserve, don't pad (UI-STANDARDS §3.2) ------------- */
.ist-tool.ist-tool.ist-tool.ist-tool .capstack { display: grid; }
.ist-tool.ist-tool.ist-tool.ist-tool .capstack > * { grid-area: 1 / 1; }

/* ---- motion: transform/opacity only, and honour the setting -------------- */
@media (prefers-reduced-motion: reduce) {
  .ist-tool.ist-tool.ist-tool.ist-tool * { animation: none !important; transition: none !important; }
}

/* ---- narrow ------------------------------------------------------------- */
@media (max-width: 480px) {
  .ist-tool.ist-tool.ist-tool.ist-tool { padding: var(--sp-3); }
  .ist-tool.ist-tool.ist-tool.ist-tool h1,
  .ist-tool.ist-tool.ist-tool.ist-tool .ist-tool-title { font-size: 23px; }

  /* T-188(c) — THE LABELS LEAVE THE BAR. Owner ruling 2026-08-04, taken off a
     rendered options sheet and then RE-taken once the type scale was checked.

     Until this block existed the ONLY things this breakpoint touched were `padding`
     and `h1`, so label headroom DECREASED monotonically with viewport width and
     clipping was structurally guaranteed at some width. Measured in the harness at
     375px, embedded, against the 45px cap on the three one-share segments.
     ⚠ CORRECTED — these were measured in the FALLBACK face, not Hanken Grotesk.
     Neither the harness nor the standalone pages load the webfont at all
     (`document.fonts.size === 0`, zero @font-face rules; the theme requests it from
     Google Fonts and the harness omits that link). With Hanken force-loaded the same
     labels measure 36 · 50 · 41 · 45 — NARROWER, so the numbers below are the WORSE
     case and the fix is sized against it. Harvest still exceeds the cap either way
     (50 vs 45), and Forced then sits at exactly zero headroom:

       shipped   10px / .1em     Clear 39 · Harvest 56 · Freeze 45 · Forced 48
       10px / tracking 0         Clear 34 · Harvest 49 · Freeze 39 · Forced 42
       10px / tracking -.01em    Clear 33 · Harvest 48 · Freeze 38 · Forced 41

     So HARVEST overflowed by 11px and FORCED by 3px, with FREEZE at exactly zero
     headroom — and shrinking the type CANNOT fix it inside the rules. DS-35 fixes
     10px as an absolute floor ("10px is the floor. Nothing renders below it"), and
     its own note records 9px being deliberately rejected as a rung. At 10px the
     label still needs 48-50px at every tracking value tried. 10px is the floor and
     10px does not fit.

     So the text leaves the bar and becomes a legend row (emitted by kit.js
     zoneGauge) — which is what this file's OWN rule 5 says ("No text on a bar,
     §4.3") and what investment-charter's zone legend already does. The legend sits
     at rung 10, on the scale.

     Scoped to <=480px deliberately: the bar is LOCKED as ONE standard across six
     surfaces including the app's StandingRoom.tsx (Q10b/DS-08), so the desktop
     drawing is untouched and diverges only where it physically cannot hold words. */
  .ist-tool.ist-tool.ist-tool.ist-tool .level.tall .seg span { display: none; }
  .ist-tool.ist-tool.ist-tool.ist-tool .level-legend { display: flex; }

  /* T-188(d) — the kit taught a pattern it did not follow. Every PER-TOOL two-column
     grid collapses here (.roles, .ogrid, .assume/.paths/.sgrid, .zones); the shared
     primitive they were all cloned from was the one that never did, leaving two
     130.5px columns at 375px with 13px labels wrapping to ~4 lines each. One line,
     one consumer (margin-zone-checker's two figure fields), fixed at the source
     instead of adding a sixth per-tool override. */
  .ist-tool.ist-tool.ist-tool.ist-tool .two { grid-template-columns: 1fr; }
}
