/* ============================================================================
   FeedForté: marketing site
   Register: authoritative-industrial. A professional instrument, not consumer SaaS.
   Flat surfaces, structural borders, monospaced numerics, no glows, no glassmorphism.
   System fonts only: zero network font requests, so the page opens fast on a
   slow connection anywhere in the world (same ethos as the offline product).
   ========================================================================== */

/* ---------- 1. Tokens ---------------------------------------------------- */

:root {
  /* Olive-tinted neutrals, matched to the app's --ff-accent #556b2f family.
     Every surface carries a little of the brand hue rather than cool steel, so
     the site and the product read as one system. */
  --ground:   #ebeee4;
  --surface:  #f6f8f1;
  --panel:    #eef1e7;
  --head:     #e4e8d9;
  --sunken:   #dee3d1;

  --ink:      #171a12;
  --ink2:     #4d5540;
  /* The brand's muted tier is #7d8994. At the 9–13px sizes it is actually used
     at, that is ~3.1:1 and misses the AA contrast floor, so the web tier is
     darkened while staying below --ink2. */
  --ink3:     #5c6650;

  --line:     #ccd3bd;
  --rail:     #9aa588;

  /* brand */
  --accent:      #556b2f;  /* olive, links, active, totals */
  --accent-soft: #e6eed6;
  --action:      #4a6320;  /* deeper olive, primary surfaces */
  /* text that sits ON an --action fill. The fill inverts between themes, so the
     ink on it must invert too, otherwise white-on-olive is 3.05:1 in dark. */
  --on-action:   #ffffff;
  --on-action-2: #d3e2b6;  /* the muted label tier on an --action fill */
  --deep:        #0f5c2e;  /* deep green, headings on light */
  --amber:       #f0b820;  /* attention / primary CTA fill */
  --amber-deep:  #c8930c;

  /* status: always paired with a glyph, never colour alone */
  --ok:   #1f7a34;
  --warn: #b8720a;
  --crit: #b3261e;

  /* dark chrome (used for inverted sections in BOTH themes): deep olive,
     taken from the product's splash background rather than the steel header */
  --chrome-a: #262d1b;
  --chrome-b: #353f24;
  --chrome-ink:  #f1f4e8;
  --chrome-ink2: #b7c0a4;
  --chrome-line: #46512f;

  --maxw: 1180px;
  --radius: 5px;
  --t: 180ms cubic-bezier(.2,.7,.3,1);

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", "Courier New", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif;

  color-scheme: light;
}

:root[data-theme="dark"] {
  --ground:   #101208;
  --surface:  #181c10;
  --panel:    #1e2315;
  --head:     #262d1a;
  --sunken:   #13160c;

  --ink:      #edf1e3;
  --ink2:     #adb79c;
  --ink3:     #8b9679;   /* light enough to clear AA on the dark olive surface */

  --line:     #30381f;
  --rail:     #454f2f;

  --accent:      #9dbb63;
  --accent-soft: #1e2a16;
  --action:      #7f9e4a;
  --on-action:   #10160a;   /* dark ink on the bright olive fill */
  --on-action-2: #223010;
  --deep:        #7fc79a;
  --amber:       #f0b820;
  --amber-deep:  #d8a30f;

  --ok:   #4fbf6a;
  --warn: #e0a33a;
  --crit: #e2695f;

  /* The chrome bands must stay ABOVE the page surfaces. At the light-theme
     values they landed within one step of --band-panel in dark mode and the
     alternating section rhythm disappeared, so they are lifted here. */
  --chrome-a: #2d3520;
  --chrome-b: #3b462a;

  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:#101208; --surface:#181c10; --panel:#1e2315; --head:#262d1a; --sunken:#13160c;
    --ink:#edf1e3; --ink2:#adb79c; --ink3:#8b9679;
    --line:#30381f; --rail:#454f2f;
    --accent:#9dbb63; --accent-soft:#1e2a16; --action:#7f9e4a; --deep:#8fd0a4;
    --on-action:#10160a; --on-action-2:#223010;
    --ok:#4fbf6a; --warn:#e0a33a; --crit:#e2695f;
    --chrome-a:#2d3520; --chrome-b:#3b462a;
    color-scheme: dark;
  }
}

/* ---------- 2. Reset + base --------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 126px;   /* clears the 110px sticky header */
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { max-width: 100%; display: block; }

h1, h2, h3, h4 {
  margin: 0;
  line-height: 1.12;
  letter-spacing: -.022em;
  font-weight: 800;
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }

::selection { background: var(--amber); color: #14181c; }

:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 2px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--amber); color: #14181c;
  padding: 12px 18px; font-weight: 700;
}
.skip:focus { left: 8px; top: 8px; }

/* every number on this site is monospaced + column-aligned: the instrument voice */
.num, .stat-val, .mock td.n, .mock .pct {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ---------- 3. Layout primitives ---------------------------------------- */

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 22px; }
.wrap-narrow { max-width: 800px; }

section { position: relative; }

.band { padding: clamp(56px, 8vw, 104px) 0; border-top: 1px solid var(--line); }
.band-surface { background: var(--surface); }
.band-panel   { background: var(--panel); }

/* inverted band: dark steel chrome, identical in both themes */
.band-dark {
  background: linear-gradient(180deg, var(--chrome-a), var(--chrome-b));
  color: var(--chrome-ink);
  border-top: 2px solid var(--amber);
  border-bottom: 1px solid #0c1219;
}
.band-dark h2, .band-dark h3 { color: #fff; }
.band-dark .lead, .band-dark p { color: var(--chrome-ink2); }
.band-dark .eyebrow { color: var(--amber); }

.eyebrow {
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 9px;
}
.eyebrow::before {
  content: "";
  width: 22px; height: 2px;
  background: var(--amber);
  flex: 0 0 22px;
}

h2.hh { font-size: clamp(27px, 4.1vw, 43px); }
h3.hs { font-size: clamp(19px, 2.2vw, 23px); letter-spacing: -.015em; }

.lead {
  font-size: clamp(16px, 1.75vw, 18.5px);
  color: var(--ink2);
  max-width: 62ch;
  margin-top: 16px;
}

.sec-head { max-width: 66ch; margin-bottom: clamp(34px, 4.5vw, 54px); }

.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* ---------- 4. Buttons --------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 22px;
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: .012em;
  border-radius: var(--radius);
  border: 1.5px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--t), border-color var(--t), color var(--t), transform var(--t);
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }

/* Primary = amber fill with near-black text.
   The brand pairs amber with white, but that is ~1.9:1 and fails the AA floor.
   Dark ink on amber is ~11:1 and keeps the brand colour. */
.btn-primary { background: var(--amber); color: #14181c; border-color: var(--amber); }
.btn-primary:hover { background: var(--amber-deep); border-color: var(--amber-deep); }

.btn-solid { background: var(--action); color: var(--on-action); border-color: var(--action); }
.btn-solid:hover { filter: brightness(1.1); }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--rail); }
.btn-ghost:hover { border-color: var(--ink); background: var(--sunken); }

/* the hero is dark chrome too: without it the ghost button rendered
   near-black on near-black (1.26:1) */
.band-dark .btn-ghost, .hero .btn-ghost { color: #fff; border-color: #5c6b3f; }
.band-dark .btn-ghost:hover, .hero .btn-ghost:hover { border-color: #fff; background: rgba(255,255,255,.07); }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

.btn .ic { width: 17px; height: 17px; flex: 0 0 17px; }

/* ---------- 5. Header ---------------------------------------------------- */

.site-head {
  position: sticky; top: 0; z-index: 100;
  background: linear-gradient(180deg, var(--chrome-a), #2f3823);
  border-bottom: 2px solid var(--amber);
}
.head-in {
  display: flex; align-items: center; gap: 20px;
  height: 110px;
}
.brand { display: flex; align-items: center; flex: 0 0 auto; margin-right: auto; }
.brand img { height: 92px; width: auto; }

.nav { display: flex; align-items: center; gap: 4px; }
.nav a {
  color: var(--chrome-ink2);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 600;
  padding: 8px 11px;
  border-radius: 4px;
  transition: color var(--t), background var(--t);
}
.nav a:hover { color: #fff; background: rgba(255,255,255,.08); }

.head-cta { display: flex; align-items: center; gap: 8px; }
.head-cta .btn { padding: 9px 15px; font-size: 13.5px; }

.icon-btn {
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1.5px solid #4b5733;
  border-radius: 4px;
  color: var(--chrome-ink2);
  cursor: pointer;
  transition: border-color var(--t), color var(--t);
}
.icon-btn:hover { color: #fff; border-color: #93a07c; }
.icon-btn svg { width: 17px; height: 17px; }
@media (prefers-color-scheme: dark) {
}

.burger { display: none; }

/* the old slide-down nav is replaced by #mobile-menu: see section 20 */

/* ---------- 6. Hero ------------------------------------------------------ */

.hero {
  background: linear-gradient(170deg, #232a19 0%, #303a22 46%, #3b472a 100%);
  color: #fff;
  border-bottom: 1px solid #10130a;
  padding: clamp(48px, 7vw, 84px) 0 clamp(56px, 7vw, 90px);
  position: relative;
  overflow: hidden;
}
/* faint structural grid: engineering paper, not decoration */
.hero::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.028) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(ellipse 90% 70% at 30% 0%, #000 20%, transparent 78%);
  pointer-events: none;
}
.hero .wrap { position: relative; z-index: 1; }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr);
  gap: clamp(34px, 5vw, 62px);
  align-items: center;
}

.hero h1 {
  font-size: clamp(33px, 5.4vw, 58px);
  letter-spacing: -.03em;
  color: #fff;
}
/* NOT inline-block. It carries no background, padding or transform: only a
   colour, but inline-block creates a line-break opportunity after it, so the
   full stop that follows </span> wrapped onto a line of its own and rendered
   as a lone white dot under the headline. */
.hero h1 .hl { color: var(--amber); }
.hero .lead { color: #cbd4bb; font-size: clamp(16.5px, 1.85vw, 19px); max-width: 54ch; }

.hero-tag {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--amber);
  border: 1px solid #57643a;
  border-left: 3px solid var(--amber);
  padding: 7px 13px;
  border-radius: 3px;
  margin-bottom: 22px;
}

.hero-points {
  list-style: none;
  margin: 30px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.hero-points li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 14.5px; color: #ccd6b9;
}
.hero-points svg { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 3px; color: var(--amber); }

.hero-note {
  margin-top: 18px;
  font-size: 13px;
  color: #c2ceae;
}
/* The note sits on the dark hero, where the muted grey would swallow a link. */
.hero-note a {
  color: var(--amber); font-weight: 700;
  text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.hero-note a:hover { color: #fff; }

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
}

/* ---------- 7. The app mock (scripted demo) ------------------------------ */
/* A faithful, responsive rebuild of the real formulation screen in HTML/CSS.
   Deliberately NOT a screenshot: no customer data can leak, it stays sharp on
   any display, and it can animate the one moment that sells the product. */

.mock {
  background: var(--surface);
  border: 1.5px solid #0d1319;
  border-radius: 7px;
  overflow: hidden;
  box-shadow: 0 18px 44px -20px rgba(0,0,0,.6);
  font-size: 12px;
  color: var(--ink);
  /* the panes stack on the MOCK's own width, not the viewport's, so the demo
     never crushes its columns wherever it happens to be placed */
  container-type: inline-size;

  /* The PRODUCT has no dark mode. This block depicts the real application, so
     it pins the light tokens locally and stays light whatever theme the site
     is in, otherwise dark mode would show a screen that does not exist.
     Same reasoning as .rpt, which depicts a printed page. */
  --surface: #f6f8fa; --panel: #eef1f5; --head: #e4e9ee; --sunken: #dde3ea;
  --ink: #141a20; --ink2: #4b5763; --ink3: #5b6672;
  --line: #ccd4dc; --rail: #9aa6b1;
  --accent: #556b2f; --action: #4a6320;
  --on-action: #ffffff; --on-action-2: #d3e2b6;
  --ok: #1f7a34; --warn: #b8720a; --crit: #b3261e;
}
.mock-bar {
  background: linear-gradient(180deg, #1c2532, #182029);
  border-bottom: 2px solid var(--action);
  padding: 8px 11px;
  display: flex; align-items: center; gap: 10px;
}
.mock-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: #3d4b5c; flex: 0 0 8px; }
.mock-bar .ttl {
  color: #cfd8e3; font-size: 10.5px; font-weight: 800;
  letter-spacing: .13em; text-transform: uppercase;
}
.mock-bar .spacer { margin-left: auto; }

.mock-metrics {
  display: flex; gap: 1px;
  background: var(--line);
  border-bottom: 1px solid var(--line);
}
.mock-metric {
  flex: 1; min-width: 0;
  background: var(--head);
  padding: 7px 10px;
}
.mock-metric .k {
  font-size: 9.5px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mock-metric .v {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 14px; font-weight: 700; color: var(--ink);
  margin-top: 2px;
}
.mock-metric.gold { background: var(--action); }
.mock-metric.gold .k { color: var(--on-action-2); }
.mock-metric.gold .v { color: var(--on-action); }
.mock-metric.delta .v { color: var(--ink2); }
/* darkened: var(--ok) measured 4.42:1 on the metric strip's fill */
.mock-metric.delta.good .v { color: #175c28; }

.mock-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line);
}
.mock-pane { background: var(--surface); min-width: 0; }
.mock-pane-hd {
  background: var(--head);
  border-bottom: 1px solid var(--line);
  padding: 6px 10px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink2);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}

.mock table { width: 100%; border-collapse: collapse; }
.mock th {
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ink2);
  text-align: right; padding: 5px 8px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.mock th:first-child, .mock td:first-child { text-align: left; }
.mock td {
  padding: 4px 8px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
  font-size: 11.5px;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mock td.name { max-width: 0; width: 46%; color: var(--ink2); font-weight: 400; }
.mock tr.used td.name { color: var(--ink); font-weight: 700; }
.mock tr.used { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.mock tr.used td.n { color: var(--action); font-weight: 700; }

.mock .pct { transition: opacity 260ms ease; }
.mock .empty { color: var(--ink3); }

/* ---------- 7b. Dry-matter basis demo ----------------------------------- */
/* The basis selector is the product's most distinctive control, so it is
   reproduced here at full size and made to actually work: the visitor flips
   it and watches the same ration re-read itself. Everything inherits .mock,
   which pins the light product tokens. */

.dm-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--head);
  border-bottom: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  padding: 9px 11px;
}
.dm-lbl { font-size: 11.5px; font-weight: 800; color: var(--ink2); white-space: nowrap; }
.dm-sel {
  font-family: inherit; font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; gap: 10px;
  min-width: 152px;
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--rail); border-radius: 4px;
  padding: 6px 9px;
  cursor: pointer;
  transition: border-color var(--t), box-shadow var(--t);
}
.dm-sel svg { width: 13px; height: 13px; margin-left: auto; color: var(--ink2); flex: 0 0 13px; }
.dm-sel:hover { border-color: var(--action); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent); }
.dm-sel:focus-visible { outline: 3px solid var(--amber); outline-offset: 2px; }
.dm-note { font-size: 11px; color: var(--ink2); }

.dm-demo table { table-layout: fixed; }
.dm-demo td { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.dm-demo td.name { font-family: var(--sans); width: 40%; }
.dm-demo td.name .u { color: var(--ink3); font-weight: 400; font-size: 10.5px; }
/* Value cell laid out like the application's: a fixed chip slot pinned left and
   the number right-aligned, so the status marks form one clean vertical line
   instead of drifting with the width of each number. The flex goes on a span,
   NOT the <td>: `display:flex` on a cell drops table-cell layout and the
   browser re-wraps it in an anonymous cell, which knocks the column out. */
.dm-demo td.n .vw { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.dm-demo td.n .cs { flex: 0 0 15px; display: flex; align-items: center; }
.dm-demo td.n b { font-weight: 700; color: var(--ink); }
.dm-demo tr.bind { background: color-mix(in srgb, var(--crit) 7%, transparent); }
.dm-demo tr.bind td.name { font-weight: 700; color: var(--ink); }

.dm-foot {
  border-top: 1px solid var(--line); background: var(--panel);
  padding: 10px 11px; font-size: 11.5px; color: var(--ink2); line-height: 1.55;
}
.dm-foot b { color: var(--ink); font-weight: 800; }

@container (max-width: 420px) {
  .dm-demo td.name { width: 46%; }
  .dm-note { display: none; }
}

.chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: 3px;
  font-size: 9.5px; font-weight: 800; line-height: 1;
  vertical-align: middle;
}
/* the darker green, matching .pill-ok: var(--ok) on this tint measures 4.46:1,
   just under AA for the 9.5px glyph */
.chip-ok   { background: #d9efdd; color: #175c28; }
/* darkened to match .pill-warn: var(--warn) measured 3.36:1 on this tint */
.chip-warn { background: #f8efd8; color: #7d4e06; }
.chip-crit { background: #f7dedb; color: #971f14; }
.chip-idle { background: var(--sunken); color: var(--ink2); }
/* no dark-theme chip overrides: chips only appear inside .mock, which is
   pinned to the light tokens above because the product has no dark mode */

.mock-foot {
  border-top: 1px solid var(--line);
  background: var(--panel);
  padding: 8px 11px;
  display: flex; align-items: center; gap: 10px;
}
.mock-solve {
  font-family: inherit;
  background: var(--action); color: var(--on-action);
  border: 1.5px solid var(--action);
  border-radius: 4px;
  padding: 7px 16px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  cursor: pointer;
  transition: filter var(--t), transform var(--t);
}
.mock-solve:hover { filter: brightness(1.12); }
.mock-solve:active { transform: translateY(1px); }
.mock-solve[disabled] { opacity: .55; cursor: default; }
.mock-status {
  font-size: 11px; font-weight: 700;
  padding: 4px 9px; border-radius: 3px;
  background: var(--sunken); color: var(--ink2);
  margin-left: auto;
}
.mock-status.ok { background: #d9efdd; color: #175c28; }

.mock-hint {
  text-align: center;
  font-size: 12.5px;
  color: #c2ceae;
  /* 13px before. The Inclusion card hangs under the window in this gap, which
     is the one band that is empty at EVERY width - beside the window there is
     155px of room at 1440 but only 34px at 1000, so no side placement holds. */
  margin-top: 108px;
}

@container (max-width: 470px) {
  .mock-body { grid-template-columns: 1fr; }
}
@container (max-width: 400px) {
  .mock-metric .v { font-size: 12.5px; }
  .mock td { font-size: 11px; padding: 4px 6px; }
}
/* fallback for engines without container queries */
@supports not (container-type: inline-size) {
  @media (max-width: 1100px) and (min-width: 901px) { .mock-body { grid-template-columns: 1fr; } }
  @media (max-width: 620px) {
    .mock-body { grid-template-columns: 1fr; }
    .mock-metric .v { font-size: 12.5px; }
    .mock td { font-size: 11px; padding: 4px 6px; }
  }
}

/* ---------- 8. Stat strip ------------------------------------------------ */

.stat-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.stat {
  background: var(--surface);
  padding: 22px 18px;
}
.stat-val {
  font-size: clamp(21px, 2.9vw, 30px);
  font-weight: 800;
  color: var(--deep);
  letter-spacing: -.02em;
}
.stat-k {
  font-size: 12px; color: var(--ink2); margin-top: 6px; line-height: 1.45;
}
@media (max-width: 760px) { .stat-strip { grid-template-columns: repeat(2, 1fr); } }

/* ---------- 9. Feature cards -------------------------------------------- */

.grid { display: grid; gap: 18px; }
.g2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.g3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.g4 { grid-template-columns: repeat(4, minmax(0,1fr)); }

@media (max-width: 980px) { .g4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 860px) { .g3 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 620px) {
  .g2, .g3, .g4 { grid-template-columns: 1fr; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 22px 20px;
  transition: border-color var(--t), background var(--t);
}
.card:hover { border-left-color: var(--amber); }
.card h3 {
  font-size: 16px; font-weight: 800; letter-spacing: -.01em;
  margin-bottom: 8px;
}
.card p { font-size: 14px; color: var(--ink2); }
.card-lnk { display: inline-block; margin-top: 2px; font-weight: 700; color: var(--amber); white-space: nowrap; }
.card-lnk:hover { text-decoration: underline; }

.card-ic {
  width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--accent);
  margin-bottom: 14px;
}
.card-ic svg { width: 17px; height: 17px; }

.band-dark .card {
  background: rgba(255,255,255,.035);
  border-color: var(--chrome-line);
  border-left-color: var(--amber);
}
.band-dark .card h3 { color: #fff; }
.band-dark .card p { color: var(--chrome-ink2); }
.band-dark .card-ic { background: rgba(255,255,255,.05); border-color: var(--chrome-line); color: var(--amber); }

/* split feature rows */
.split {
  display: grid;
  grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: clamp(30px, 5vw, 64px);
  align-items: center;
}
.split.flip > *:first-child { order: 2; }
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
  .split.flip > *:first-child { order: 0; }
}

.ticks { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 12px; }
.ticks li { display: flex; gap: 11px; align-items: flex-start; font-size: 14.5px; color: var(--ink2); }
.ticks svg { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 3px; color: var(--accent); }
.ticks b { color: var(--ink); font-weight: 700; }
/* on dark chrome the olive accent and --ink both disappear */
.band-dark .ticks svg { color: var(--amber); }
.band-dark .ticks b   { color: #fff; }
.band-dark .ticks li  { color: var(--chrome-ink2); }

/* ---------- 10. Disclaimer note ------------------------------------------ */
/* Was section 10, the savings calculator, removed at the client's request. Only
   .calc-note survives: the species section uses it for its honesty note. It is
   deliberately readable rather than greyed to the point of being decorative. */

.calc-note {
  margin-top: 16px;
  font-size: 13px;
  color: var(--ink2);
  line-height: 1.6;
  border-left: 2px solid var(--rail);
  padding-left: 13px;
}

/* ---------- 11. Species -------------------------------------------------- */

.spec-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px 18px;
  transition: border-color var(--t);
}
.spec-card:hover { border-color: var(--accent); }
.spec-card h3 {
  font-size: 14.5px; font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--deep);
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  font-family: var(--mono);
  font-size: 11px;
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--panel);
  color: var(--ink2);
  white-space: nowrap;
}

/* ---------- 11b. Capability list ----------------------------------------- */

.cap-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(18px, 3vw, 34px);
}
@media (max-width: 1020px) { .cap-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .cap-grid { grid-template-columns: 1fr; } }

.cap-col h3 {
  font-size: 12px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--deep);
  padding-bottom: 8px; margin-bottom: 12px;
  border-bottom: 2px solid var(--accent);
}
.cap-col h3 + .cap { margin-bottom: 26px; }
.cap-col h3:not(:first-child) { margin-top: 0; }

ul.cap { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
ul.cap li {
  position: relative;
  padding-left: 15px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink2);
}
ul.cap li::before {
  content: "";
  position: absolute; left: 0; top: 8px;
  width: 6px; height: 6px;
  background: var(--amber);
}
ul.cap b { color: var(--ink); font-weight: 700; }

/* ---------- 12. Report mock --------------------------------------------- */

/* This block simulates a PRINTED PAGE, so it is deliberately theme-independent:
   fixed print colours, never the --deep/--accent tokens, which invert in dark
   mode and would put pale green on white paper. */
.rpt {
  background: #fff;
  border: 1px solid #9aa6b1;
  border-radius: 4px;
  overflow: hidden;
  color: #1a2028;
  box-shadow: 0 14px 34px -18px rgba(0,0,0,.45);
  font-size: 11px;
}
.rpt-lh {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  padding: 14px 16px 12px;
  border-bottom: 2px solid #0f5c2e;
}
.rpt-lh img { height: 42px; }
.rpt-lh .meta { text-align: right; font-size: 9.5px; color: #4c5764; line-height: 1.65; }
.rpt-lh .meta b { color: #0f5c2e; font-size: 11px; display: block; }
.rpt-ttl {
  background: linear-gradient(90deg, #0f5c2e, #17784a);
  color: #fff;
  padding: 7px 16px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .13em; text-transform: uppercase;
  display: flex; justify-content: space-between; gap: 12px;
}
.rpt-sec {
  padding: 5px 16px;
  background: #eef2f5;
  border-left: 4px solid #556b2f;
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: #33404d;
  margin-top: 2px;
}
.rpt table { width: 100%; border-collapse: collapse; }
.rpt th {
  background: #0f5c2e; color: #fff;
  font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 16px; text-align: right;
}
.rpt th:first-child, .rpt td:first-child { text-align: left; }
.rpt td {
  padding: 3.5px 16px; text-align: right;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 10px;
  color: #1a2028;
  border-bottom: 1px solid #e6ebef;
}
.rpt td:first-child { font-family: var(--sans); }
.rpt tr:nth-child(even) td { background: #f5f8fa; }
.rpt tr.tot td { font-weight: 800; border-top: 1.5px solid #0f5c2e; background: #eaf1ec !important; }
.rpt-foot { padding: 8px 16px; font-size: 9.5px; color: #5c6771; border-top: 1px solid #e6ebef; display: flex; justify-content: space-between; }

/* ---------- 13. Comparison table ---------------------------------------- */

.cmp-wrap { overflow-x: auto; border: 1.5px solid var(--rail); border-radius: 6px; -webkit-overflow-scrolling: touch; }
.cmp { width: 100%; border-collapse: collapse; min-width: 560px; background: var(--surface); }
.cmp th, .cmp td { padding: 13px 16px; text-align: left; border-bottom: 1px solid var(--line); font-size: 14px; }
.cmp thead th {
  background: var(--head);
  font-size: 11px; font-weight: 800; letter-spacing: .11em; text-transform: uppercase;
  color: var(--ink2);
  border-bottom: 2px solid var(--rail);
}
.cmp thead th.us { background: var(--action); color: var(--on-action); }
.cmp tbody th { font-weight: 600; color: var(--ink); width: 40%; }
.cmp td { color: var(--ink2); }
.cmp td.us { background: var(--accent-soft); color: var(--ink); font-weight: 700; width: 30%; }
:root[data-theme="dark"] .cmp td.us { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.cmp tr:last-child th, .cmp tr:last-child td { border-bottom: 0; }
.cmp .yes { color: var(--ok); font-weight: 800; }
.cmp-note { font-size: 12.5px; color: var(--chrome-ink2); margin-top: 14px; }

/* ---------- 14. Founder -------------------------------------------------- */

.founder {
  display: grid;
  grid-template-columns: 210px minmax(0,1fr);
  gap: clamp(22px, 4vw, 40px);
  align-items: start;
}
@media (max-width: 700px) { .founder { grid-template-columns: 1fr; } }

.portrait {
  position: relative;
  aspect-ratio: 1;
  border: 1.5px solid var(--chrome-line);
  border-radius: 6px;
  background: rgba(255,255,255,.05);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  max-width: 210px;
  box-shadow: 0 16px 36px -18px rgba(0,0,0,.55);
}
/* the photo overlays the monogram; if it fails to load it removes itself
   (onerror) and the monogram shows instead */
.portrait img {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
  background: #fff;   /* the photograph has a white ground */
}
.portrait .ph {
  font-family: var(--mono);
  font-size: 34px; font-weight: 700; color: var(--amber); letter-spacing: .06em;
}
.quote {
  font-size: clamp(17px, 2.1vw, 21px);
  line-height: 1.5;
  color: #fff;
  font-weight: 500;
  letter-spacing: -.012em;
  border-left: 3px solid var(--amber);
  padding-left: 20px;
  text-wrap: pretty;
}
.sig { margin-top: 20px; font-size: 14px; color: var(--chrome-ink2); }
.sig b { color: #fff; display: block; font-size: 15.5px; }
/* qualifications sit under the name, quieter and letter-spaced like a
   credential line rather than a job title */
.sig .creds {
  display: block; margin-top: 5px;
  font-size: 14px; font-weight: 700; letter-spacing: .01em;
  color: var(--chrome-ink);
}
/* the separators sit between qualifications, not inside them, so they are
   quieter than the text they divide */
.sig .creds i { font-style: normal; color: var(--amber); margin: 0 5px; }

/* ---------- 15. FAQ ------------------------------------------------------ */

.faq { border-top: 1px solid var(--line); }
.faq details {
  border-bottom: 1px solid var(--line);
}
.faq summary {
  cursor: pointer;
  list-style: none;
  padding: 19px 44px 19px 0;
  font-size: 16px; font-weight: 700;
  color: var(--ink);
  position: relative;
  transition: color var(--t);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--accent); }
.faq summary::after {
  content: "";
  position: absolute; right: 8px; top: 50%;
  width: 11px; height: 11px;
  border-right: 2px solid var(--ink3);
  border-bottom: 2px solid var(--ink3);
  transform: translateY(-70%) rotate(45deg);
  transition: transform var(--t);
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq .ans { padding: 0 8px 22px 0; color: var(--ink2); font-size: 15px; max-width: 74ch; }
.faq .ans p + p { margin-top: 12px; }

/* ---------- 16. CTA + footer -------------------------------------------- */

.cta-box {
  border: 1.5px solid var(--chrome-line);
  border-left: 4px solid var(--amber);
  border-radius: 6px;
  background: rgba(255,255,255,.04);
  padding: clamp(26px, 4vw, 40px);
}
.contact-list { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 14px; }
.contact-list li { display: flex; align-items: center; gap: 13px; }
.contact-list svg { width: 18px; height: 18px; flex: 0 0 18px; color: var(--amber); }
.contact-list a, .contact-list span { color: #fff; text-decoration: none; font-size: 15.5px; font-weight: 600; word-break: break-word; }
.contact-list a:hover { text-decoration: underline; }
.contact-list small { display: block; color: var(--chrome-ink2); font-size: 12.5px; font-weight: 400; }

.site-foot {
  background: var(--chrome-a);
  color: var(--chrome-ink2);
  border-top: 2px solid var(--amber);
  padding: 34px 0 28px;
  font-size: 13px;
}
/* Four columns: who it is, two groups of links, and how to reach him. The old
   footer was three items in one flex row, which left a wide dead gap in the
   middle and gave a visitor nothing to do at the end of the page. */
.foot-in {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(2, minmax(0, 1fr)) minmax(0, 1.2fr);
  gap: 30px 38px;
  align-items: start;
}
/* width:auto is load-bearing. The <img> carries width="685" height="267"
   attributes, which act as the SPECIFIED width, so with only a height set,
   the browser clamped that 685 to the column and applied the height
   independently, stretching the logo to an aspect of 5.8 against its true
   2.57. It has been stretched in the footer all along. */
.site-foot img { height: 56px; width: auto; opacity: .95; display: block; }
/* :not(.btn), this blanket colour was repainting the Request-pricing button's
   text muted sage ON amber: 1.04:1, effectively invisible. Buttons keep their
   own dark ink (9.84:1). */
.site-foot a:not(.btn) { color: var(--chrome-ink2); text-decoration: none; }
.site-foot a:not(.btn):hover { color: #fff; text-decoration: underline; }

/* no max-width: the grid track already sets a sensible measure, and capping
   the content left a 126px dead gap inside its own column */
.foot-brand { min-width: 0; }
.foot-tag {
  margin: 11px 0 0; font-size: 11.5px; font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase; color: var(--amber);
}
.foot-blurb { margin: 9px 0 0; font-size: 13px; line-height: 1.6; color: var(--chrome-ink2); }

.foot-col { display: flex; flex-direction: column; align-items: flex-start; }
.foot-h {
  margin: 0 0 4px; font-size: 11px; font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase; color: #fff;
}
.foot-col a { padding: 7px 0; font-size: 13px; }

.foot-who { margin: 0 0 4px; font-size: 13px; font-weight: 700; color: #fff; }
.foot-who span { display: block; font-size: 11.5px; font-weight: 600; color: var(--chrome-ink2); margin-top: 2px; }
.foot-cta { margin-top: 12px; }
.foot-cta:hover { text-decoration: none; }

/* the legal line sits under a rule, away from the columns */
.foot-base {
  display: flex; flex-wrap: wrap; gap: 8px 26px;
  justify-content: space-between; align-items: baseline;
  margin-top: 30px; padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,.12);
  font-size: 12px; color: var(--chrome-ink2);
}
.foot-note { max-width: 62ch; }
.foot-muted { font-size: 12px; color: var(--chrome-ink2); }

@media (max-width: 900px) {
  .foot-in { grid-template-columns: 1fr 1fr; }
  .foot-brand { grid-column: 1 / -1; }
  .foot-contact { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .foot-in { grid-template-columns: 1fr; gap: 24px; }
}

/* ---------- 16b. Depth / 3D ---------------------------------------------
   A real perspective stage rather than a flat drop-shadow. Restrained on
   purpose: the brand register rules out consumer-SaaS decoration, so the angles
   are small, the motion is state-only, and there are no glows. This is how a CAD
   or instrument product is photographed: turned slightly into the light.   */

.scene {
  perspective: 1700px;
  perspective-origin: 50% 38%;
}

.tilt3d {
  position: relative;
  transform-style: preserve-3d;
  transform: rotateX(5.5deg) rotateY(-12deg) rotateZ(.5deg) translateZ(0);
  transition: transform 520ms cubic-bezier(.22,.68,.28,1);
  will-change: transform;
}
.scene:hover .tilt3d { transform: rotateX(3deg) rotateY(-6deg) rotateZ(.2deg); }

/* the extruded right-hand edge: an actual rotated face, not a gradient fake */
.tilt3d::after {
  content: "";
  position: absolute;
  top: 3px; bottom: 3px; right: 0;
  width: 16px;
  transform-origin: right center;
  transform: rotateY(-90deg);
  background: linear-gradient(90deg, #10130a, #232a19 55%, #2f381f);
  border-radius: 0 3px 3px 0;
  pointer-events: none;
}
/* bottom face, so the object reads as a solid slab */
.tilt3d::before {
  content: "";
  position: absolute;
  left: 4px; right: 4px; bottom: 0;
  height: 14px;
  transform-origin: center bottom;
  transform: rotateX(-90deg);
  background: linear-gradient(180deg, #1b2113, #10130a);
  pointer-events: none;
}

/* contact shadow on the floor beneath the slab */
.tilt3d-shadow {
  position: absolute;
  left: 6%; right: 2%; bottom: -26px; height: 44px;
  background: radial-gradient(ellipse at 50% 50%, rgba(0,0,0,.5), transparent 72%);
  filter: blur(11px);
  transform: translateZ(-60px);
  pointer-events: none;
  z-index: -1;
}

/* a second and third screen sitting behind the first, in real depth */
.shot-stack { position: relative; transform-style: preserve-3d; }
.shot-stack > .shot-back {
  position: absolute;
  inset: 0;
  border-radius: 7px;
  border: 1.5px solid rgba(255,255,255,.10);
  background: linear-gradient(160deg, #39422a, #262d1b);
  pointer-events: none;
}
.shot-stack > .shot-back.b1 { transform: translate3d(26px, -20px, -90px); }
.shot-stack > .shot-back.b2 { transform: translate3d(50px, -38px, -170px); opacity: .62; }

/* the hero's own tilt is gentler: it sits beside body copy and must stay readable */
.hero .tilt3d { transform: rotateX(4deg) rotateY(-8.5deg) rotateZ(.35deg); }
.hero .scene:hover .tilt3d { transform: rotateX(2deg) rotateY(-4deg) rotateZ(.15deg); }

/* .soft3d: for the windows a visitor actually READS and presses. Same slab,
   a much shallower angle, and it straightens completely on hover so the
   depth is decoration on approach and never an obstacle in use. */
.soft3d { perspective: 2400px; perspective-origin: 50% 44%; }
.soft3d .tilt3d { transform: rotateX(2.6deg) rotateY(-5deg) rotateZ(.18deg); }
.soft3d:hover .tilt3d { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); }
.soft3d.flipped .tilt3d { transform: rotateX(2.6deg) rotateY(5deg) rotateZ(-.18deg); }
.soft3d.flipped:hover .tilt3d { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); }
/* a window with focus inside it must be square-on: a rotated text field is
   unusable, and the home screen's Focus Mode is a real control */
.soft3d:focus-within .tilt3d { transform: none !important; }
.soft3d .tilt3d::after { width: 10px; }
.soft3d .tilt3d::before { height: 9px; }
/* mirrored extrusion: the light has to come from the other side when it leans right */
.soft3d.flipped .tilt3d::after {
  right: auto; left: 0; transform-origin: left center; transform: rotateY(90deg);
  border-radius: 3px 0 0 3px;
  background: linear-gradient(270deg, #10130a, #232a19 55%, #2f381f);
}

@media (max-width: 900px) {
  /* on a phone the object fills the width; an angle just costs legibility */
  .scene { perspective: none; }
  .tilt3d, .hero .tilt3d, .scene:hover .tilt3d, .hero .scene:hover .tilt3d,
  .soft3d .tilt3d, .soft3d:hover .tilt3d,
  .soft3d.flipped .tilt3d, .soft3d.flipped:hover .tilt3d { transform: none; }
  .tilt3d::after, .tilt3d::before, .tilt3d-shadow { display: none; }
  .shot-stack > .shot-back { display: none; }
}

/* ---------- 16b-ii. Scroll-driven 3D --------------------------------------
   The panel turns as it travels through the viewport and settles square-on,
   and the stacked screens behind it separate in depth at their own rate.

   Native CSS scroll-driven animation: no library, no scroll listener, no
   JavaScript at all, so it runs on the compositor and cannot jank. Gated on
   @supports, on a real pointer, and on reduced-motion, so anything that
   cannot do it simply keeps the static angle already defined above.       */

@supports (animation-timeline: view()) {
  @media (min-width: 901px) and (prefers-reduced-motion: no-preference) {

    .tilt3d {
      animation: ff-settle linear both;
      animation-timeline: view();
      animation-range: entry 15% cover 58%;
    }
    @keyframes ff-settle {
      from { transform: rotateX(10deg) rotateY(-19deg) rotateZ(1.1deg) translateY(30px) scale(.965); }
      to   { transform: rotateX(2.5deg) rotateY(-5deg)  rotateZ(.15deg) translateY(0)    scale(1); }
    }

    /* the two panels behind pull apart in Z as the stack comes into view */
    .shot-back.b1 {
      animation: ff-back1 linear both;
      animation-timeline: view(); animation-range: entry 15% cover 62%;
    }
    .shot-back.b2 {
      animation: ff-back2 linear both;
      animation-timeline: view(); animation-range: entry 15% cover 68%;
    }
    @keyframes ff-back1 {
      from { transform: translate3d(6px, -5px, -24px);  opacity: .35; }
      to   { transform: translate3d(30px, -23px, -104px); opacity: 1; }
    }
    @keyframes ff-back2 {
      from { transform: translate3d(10px, -8px, -44px);  opacity: .18; }
      to   { transform: translate3d(58px, -44px, -196px); opacity: .62; }
    }

    /* the watermark drifts against the scroll, which reads as real distance */
    .wm::before {
      animation: ff-drift linear both;
      animation-timeline: view(); animation-range: cover 0% cover 100%;
    }
    @keyframes ff-drift {
      from { transform: translateY(-38%) rotate(-5deg); }
      to   { transform: translateY(-62%) rotate(5deg); }
    }

    /* section content lifts out of depth instead of sliding flat */
    .rv { transform: none; }
    /* .js-scoped for the same reason as the base rule: the .in class comes from
       JS, so an unscoped hide leaves the page invisible when scripts do not run */
    .js .rv:not(.in) { opacity: 0; }
    .band .sec-head, .band .grid, .band .split, .band .calc, .band .showcase, .band .founder {
      animation: ff-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 82%;
    }
    @keyframes ff-rise {
      from { opacity: 0; transform: perspective(1200px) translate3d(0, 26px, -70px) rotateX(4.5deg); }
      to   { opacity: 1; transform: perspective(1200px) translate3d(0, 0, 0) rotateX(0); }
    }

    /* the reading windows settle from a shallower start than the hero slab */
    .soft3d .tilt3d {
      animation: ff-settle-soft linear both;
      animation-timeline: view(); animation-range: entry 12% cover 52%;
    }
    @keyframes ff-settle-soft {
      from { transform: rotateX(6deg) rotateY(-11deg) rotateZ(.6deg) translateY(22px) scale(.978); }
      to   { transform: rotateX(2.6deg) rotateY(-5deg) rotateZ(.18deg) translateY(0) scale(1); }
    }
    .soft3d.flipped .tilt3d { animation-name: ff-settle-soft-r; }
    @keyframes ff-settle-soft-r {
      from { transform: rotateX(6deg) rotateY(11deg) rotateZ(-.6deg) translateY(22px) scale(.978); }
      to   { transform: rotateX(2.6deg) rotateY(5deg) rotateZ(-.18deg) translateY(0) scale(1); }
    }

    /* capability columns arrive out of depth, each a beat behind the last */
    .cap-grid > .cap-col {
      animation: ff-rise linear both;
      animation-timeline: view(); animation-range: entry 0% entry 88%;
    }
    .cap-grid > .cap-col:nth-child(2) { animation-range: entry 0% entry 96%; }
    .cap-grid > .cap-col:nth-child(3) { animation-range: entry 0% cover 4%; }
    .cap-grid > .cap-col:nth-child(4) { animation-range: entry 0% cover 12%; }
  }
}

/* ---------- 16b-iii. Depth on the pieces you touch -----------------------
   Cards and result panels lift toward the reader rather than sliding flat,
   and a panel that has just been switched to arrives out of depth, so the
   press is acknowledged in the same visual language as the rest of the page. */

.grid, .cap-grid { perspective: 1400px; perspective-origin: 50% 40%; }

@media (prefers-reduced-motion: no-preference) and (pointer: fine) {
  .card { transform-style: preserve-3d; }
  .card:hover {
    transform: translate3d(0, -4px, 30px) rotateX(1.6deg);
    box-shadow: 0 26px 44px -22px rgba(15, 22, 8, .48);
  }

  /* The CHILDREN are what get re-created on every press, so animating them
     replays by itself; animating the container would only ever fire once. */
  .stab.on, .sc-card, .co-item {
    animation: ff-panel-in 260ms cubic-bezier(.22,.68,.28,1) both;
  }
  .co-item:nth-child(2) { animation-delay: 45ms; }
  .co-item:nth-child(3) { animation-delay: 90ms; }
  .co-item:nth-child(4) { animation-delay: 135ms; }
  .sc-card:nth-child(2) { animation-delay: 60ms; }
  @keyframes ff-panel-in {
    from { opacity: 0; transform: perspective(900px) translate3d(0, 8px, -46px) rotateX(4deg); }
    to   { opacity: 1; transform: perspective(900px) translate3d(0, 0, 0) rotateX(0); }
  }
}

/* ---------- 16b-iii. Deeper 3D: parallax, float cards, progress ----------
   The pointer parallax turns the INNER .shot-stack, never the .tilt3d: the
   scroll-driven ff-settle animation owns .tilt3d's transform, and an inline
   transform there would be silently overridden by the animation's fill.    */

.shot-stack {
  transition: transform 300ms cubic-bezier(.2,.7,.3,1);
  will-change: transform;
}

/* annotation cards floating IN FRONT of the panel at different depths.
   They depict app figures, so their colours are pinned light like .mock.  */
.float-card {
  position: absolute;
  z-index: 2;
  display: flex; flex-direction: column; gap: 1px;
  padding: 9px 14px;
  background: #f6f8fa;
  border: 1.5px solid #0d1319;
  border-left: 3px solid #4a6320;
  border-radius: 5px;
  box-shadow: 0 12px 26px -12px rgba(0,0,0,.55);
  pointer-events: none;
}
.float-card .fk {
  font-size: 8.5px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: #4b5763;
}
.float-card .fv {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 15px; font-weight: 800; color: #141a20;
}
.float-card .fv.good { color: #175c28; }
/* Both cards used to sit ON the window: fc1 (top:-18/right:-24) landed on the
   title bar and covered the formula name, and fc2 (bottom:40/left:-28) covered
   the Formulate button and two row numbers. There is no room beside the panel
   (67px of gap, and these are 92-130px wide) and the hint line sits 5px below
   it - but the band ABOVE the window is empty, so both now hang there.
   Beside it is no good either: 155px of room at 1440 but only 34px at 1000,
   and the cards still show down to 900. The band BELOW the window is the only
   one that is empty at every width, so both hang there off their original
   corners - Inclusion left, Difference right - with the caption pushed clear
   beneath them. They keep their translateZ and the bob, so the depth reads the
   same, and the bob travels upward only, away from the caption. */
/* right:0 by default - at 1000px there are only 19px between the window and
   the clipping edge of .hero, so a 24px overhang loses a corner of the card.
   The overhang comes back once there is room for it. The left card needs no
   such guard: it has 523px of margin on that side. */
.fc1 { top: calc(100% + 12px); bottom: auto; right: 0; transform: translateZ(60px); }
/* the corner overhang on both cards, only where the layout has room for it:
   below 1200 the hero column narrows and the copy sits close enough that a
   left overhang lands on it. */
@media (min-width: 1200px) { .fc1 { right: -24px; } .fc2 { left: -28px; } }
.fc2 { top: calc(100% + 12px); bottom: auto; left: 0; transform: translateZ(95px); border-left-color: #f0b820; }

/* idle bob on the separate `translate` property so it can never clobber the
   translateZ carried by `transform` */
@media (prefers-reduced-motion: no-preference) {
  .fc1 { animation: fc-bob 5.2s ease-in-out infinite alternate; }
  .fc2 { animation: fc-bob 6.8s ease-in-out .9s infinite alternate; }
}
@keyframes fc-bob { from { translate: 0 0; } to { translate: 0 -8px; } }

@media (max-width: 900px) { .float-card { display: none; } }

/* thin amber reading-progress line along the very top: instrument, not toy */
.progress {
  position: fixed; top: 0; left: 0; right: 0;
  height: 3px; z-index: 300; pointer-events: none;
}
.progress i { display: block; height: 100%; width: 0; background: var(--amber); }

/* cards lift slightly on hover: restrained, no rotation, no glow */
.card { transition: border-color var(--t), background var(--t), transform var(--t), box-shadow var(--t); }
.card:hover { transform: translateY(-3px); box-shadow: 0 12px 24px -16px rgba(15, 22, 8, .4); }

/* ---------- 16c. F watermark ---------------------------------------------
   The same device the printed reports use: the chrome F, very low contrast,
   anchored so it reads as a paper mark rather than an image.               */

/* overflow-x:clip, not hidden, clip does not create a scroll container, so the
   watermark cannot widen the page (it hangs 60px past the right edge) while
   sticky positioning and the 3D stages inside keep working. */
.wm { position: relative; isolation: isolate; overflow-x: clip; }
.wm::before {
  content: "";
  position: absolute;
  right: -60px; top: 50%;
  width: min(520px, 46vw); aspect-ratio: 164 / 159;
  transform: translateY(-50%);
  background: url(assets/f-mark.svg) center / contain no-repeat;
  opacity: .035;
  z-index: -1;
  pointer-events: none;
}
.band-dark.wm::before { opacity: .06; }
.wm-left::before { right: auto; left: -70px; }
@media (max-width: 760px) {
  .wm::before { width: 68vw; right: -22vw; opacity: .028; }
  .wm-left::before { left: -24vw; right: auto; }
}

/* ---------- 16d. App-screen showcase -------------------------------------
   Faithful recreations of each screen in HTML/CSS rather than screenshots:
   they stay sharp at any density, reflow on a phone, carry no customer data,
   and cannot go stale against a rebuild. One stage, tabbed.               */

.showcase-tabs {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: 22px;
}
.showcase-tabs button {
  font-family: inherit;
  font-size: 12.5px; font-weight: 700;
  letter-spacing: .02em;
  padding: 9px 14px;
  border-radius: 4px;
  border: 1.5px solid var(--chrome-line);
  background: rgba(255,255,255,.04);
  color: var(--chrome-ink2);
  cursor: pointer;
  transition: background var(--t), color var(--t), border-color var(--t);
  white-space: nowrap;
  min-height: 40px;
}
.showcase-tabs button:hover { color: #fff; border-color: #6f7f4e; }
.showcase-tabs button[aria-selected="true"] {
  background: var(--amber); border-color: var(--amber); color: #14181c;
}

.showcase-stage { position: relative; }
.screen { display: none; }
.screen.on { display: block; }

.screen-cap {
  margin-top: 16px;
  font-size: 13.5px;
  color: var(--chrome-ink2);
  max-width: 72ch;
}
.screen-cap b { color: #fff; font-weight: 700; }

/* --- the generic application window ------------------------------------- */

.appwin {
  background: #f6f8fa;                 /* the app is steel; it is not olive */
  border: 1.5px solid #0d1319;
  border-radius: 7px;
  overflow: hidden;
  box-shadow: 0 20px 48px -22px rgba(0,0,0,.62);
  color: #141a20;
  font-size: 12px;
  container-type: inline-size;
}
.appwin-bar {
  background: linear-gradient(180deg, #1c2532, #182029);
  border-bottom: 2px solid #4a6320;
  padding: 8px 12px;
  display: flex; align-items: center; gap: 9px;
}
.appwin-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: #3d4b5c; flex: 0 0 8px; }
.appwin-bar .t {
  color: #cfd8e3; font-size: 10.5px; font-weight: 800;
  letter-spacing: .13em; text-transform: uppercase;
}
.appwin-bar .r { margin-left: auto; color: #8b98a8; font-size: 10.5px; font-weight: 700; }

.appwin-toolbar {
  background: #e4e9ee; border-bottom: 1px solid #ccd4dc;
  padding: 6px 12px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 10.5px; color: #4b5763;
}
.appwin-toolbar .chip2 {
  padding: 3px 9px; border: 1px solid #ccd4dc; border-radius: 3px;
  background: #f6f8fa; font-weight: 700; white-space: nowrap;
}
.appwin-toolbar .chip2.go { background: #4a6320; border-color: #4a6320; color: #fff; }

.appwin table { width: 100%; border-collapse: collapse; }
.appwin th {
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: #4b5763; text-align: right; padding: 6px 10px;
  background: #e4e9ee; border-bottom: 1px solid #ccd4dc; white-space: nowrap;
}
.appwin th:first-child, .appwin td:first-child { text-align: left; }
.appwin td {
  padding: 4.5px 10px; text-align: right; font-size: 11.5px;
  border-bottom: 1px solid #eef1f5; white-space: nowrap;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
}
.appwin td:first-child { font-family: var(--sans); }
/* Text columns (Category, descriptions). The header must carry .txt too: the
   default th is right-aligned, which left the label floating over the numbers
   column instead of over its own values. */
.appwin th.txt, .appwin td.txt { text-align: left; font-family: var(--sans); }
/* max-width:0 collapsed the name column to its minimum and ellipsised real
   names ("Cereal By-Pro...") while a sibling column kept 148px of slack - the
   same trap .hs-tbl td.nm already had to undo. Names are now unclamped and the
   table scroller carries any overflow.
   text-align:left because .appwin td defaults to RIGHT and only :first-child
   and .txt restore left - so a .nm that is not the first column rendered
   right-aligned next to left-aligned neighbours in the same column. */
.appwin td.nm {
  color: #141a20; font-weight: 600; text-align: left;
  max-width: none; overflow: visible; text-overflow: clip;
}
.appwin tr.hi { background: #eef4e6; }
.appwin tr.hi td.nm { font-weight: 700; }
.appwin tr.tot td { font-weight: 800; border-top: 1.5px solid #9aa6b1; background: #eef1f5; }

/* section banner inside a screen */
.appwin .sec {
  background: #dfe4d5; color: #3b4529;
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 12px; border-bottom: 1px solid #ccd4dc;
}

/* A section divider INSIDE a table. The comparison panel used to put its
   "Cost and nutrition" block in a SECOND table in its own scroller with no
   <thead> at all - four columns of numbers under nothing - and because each
   table sized its own columns independently they stepped up to 58px right of
   the headings above them. One table with the divider as a full-width row
   makes the alignment structural rather than coincidental. */
.appwin tr.secrow td {
  background: #dfe4d5; color: #3b4529; text-align: left;
  font-family: var(--sans);
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 12px; border-bottom: 1px solid #ccd4dc;
}

/* dashboard cards (inventory) */
.appwin-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: #ccd4dc; }
.appwin-cards > div { background: #f6f8fa; padding: 9px 11px; border-left: 3px solid #4a6320; }
.appwin-cards .k { font-size: 8.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: #4b5763; }
.appwin-cards .v { font-family: var(--mono); font-size: 15px; font-weight: 800; margin-top: 3px; }
.appwin-cards .crit { border-left-color: #b3261e; } .appwin-cards .crit .v { color: #971f14; }
.appwin-cards .warn { border-left-color: #b8720a; } .appwin-cards .warn .v { color: #7d4e06; }
@container (max-width: 560px) { .appwin-cards { grid-template-columns: repeat(2, 1fr); } }

/* diagnostics screen: mirrors the real Cost Sensitivity Analysis layout */
.diag-strip {
  padding: 5px 12px;
  background: #f8f0dd;
  color: #5c4708;
  font-size: 10.5px;
  border-bottom: 1px solid #ccd4dc;
}
.diag-strip b { font-family: var(--mono); }
.diag-boxes { display: grid; grid-template-columns: 1fr 1.5fr; gap: 1px; background: #ccd4dc; }
.diag-boxes > div { background: #f6f8fa; padding: 10px 13px; min-width: 0; }
/* must outrank `.diag-boxes > div` above: a bare `.diag-obj` loses on
   specificity and the box rendered pale-green-on-white, unreadable */
.diag-boxes > div.diag-obj { background: #4a6320; }
.diag-obj .k { font-size: 8.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: #d3e2b6; }
.diag-obj .v { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 22px; font-weight: 800; color: #fff; margin-top: 2px; }
.diag-obj .v small { font-size: 11px; font-weight: 600; color: #d3e2b6; }
.diag-obj .s { font-family: var(--mono); font-size: 9.5px; color: #d3e2b6; margin-top: 3px; }
.diag-meta .k { font-size: 8.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: #4b5763; }
.diag-meta .v2 { font-size: 13px; font-weight: 800; color: #2c4a70; margin-top: 2px; }
.diag-meta .s { font-size: 10.5px; color: #4b5763; margin-top: 3px; }
.diag-meta .okc { color: #175c28; }
.diag-meta .btns { display: flex; gap: 6px; margin-top: 7px; }
@container (max-width: 560px) { .diag-boxes { grid-template-columns: 1fr; } }

/* status pills: inks darkened to clear 4.5:1 on their tinted fills at 10px */
.pill { display: inline-block; padding: 1.5px 7px; border-radius: 3px; font-size: 9.5px; font-weight: 800; font-family: var(--sans); }
.pill-ok   { background: #d9efdd; color: #175c28; }
.pill-warn { background: #f8efd8; color: #7d4e06; }
.pill-crit { background: #f7dedb; color: #971f14; }
.pill-info { background: #e2e8f0; color: #3a4a5e; }

/* horizontal bar used for days-of-cover and cost drivers */
/* ---------- The full home screen ---------------------------------------- */
/* The complete application window, rebuilt in HTML so no plant name, user name
   or photograph can leak and it stays sharp at any density. Colours are hard
   -coded like the rest of .appwin: the product has no dark mode, so a token
   here would flip with the site theme. */

.homewin { font-size: 11px; }
.homewin .tscroll { overflow-x: auto; }

.hs-brand {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: linear-gradient(180deg, #1c2532, #131a22);
  border-bottom: 2px solid #4a6320;
  padding: 9px 13px;
}
/* min() rather than a flat 108px: the global img{max-width:100%} was clamping
   the rendered width to the container while the auto height stayed at the
   unclamped figure, squashing it ~4%. Sizing inside the limit avoids the clamp. */
.hs-logo { width: min(108px, 100%); height: auto; flex: 0 0 auto; }
.hs-plant { border-left: 3px solid #f0b820; padding-left: 10px; min-width: 0; }
.hs-plant .e { display: block; font-size: 8px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: #f0b820; }
.hs-plant b { display: block; font-size: 15px; font-weight: 800; color: #fff; letter-spacing: .01em; }
.hs-plant .m { display: block; font-size: 8.5px; color: #8b98a8; margin-top: 1px; }
.hs-plant .m u { color: #cfd8e3; }
.hs-user { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.hs-av {
  width: 30px; height: 30px; flex: 0 0 30px; border-radius: 50%;
  background: #2a3542; border: 1.5px solid #4a6320; color: #9fb07f;
  display: flex; align-items: center; justify-content: center;
}
.hs-av svg { width: 19px; height: 19px; }
.hs-user b { display: block; font-size: 10.5px; font-weight: 800; color: #fff; }
.hs-user i { display: block; font-size: 8.5px; font-style: normal; color: #8b98a8; }
.hs-formulate {
  background: #4a6320; color: #fff; border-radius: 4px;
  padding: 7px 15px; font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  white-space: nowrap;
}
.hs-btns { display: flex; gap: 5px; flex-wrap: wrap; }
.hs-btns span {
  border: 1px solid #3d4b5c; border-radius: 3px; padding: 4px 7px;
  font-size: 8.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: #cfd8e3; white-space: nowrap;
}

.hs-tool {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  background: #e4e9ee; border-bottom: 1px solid #ccd4dc;
  padding: 6px 12px; font-size: 10px; color: #4b5763;
}
.hs-tool .l { font-weight: 800; white-space: nowrap; }
.hs-tool .f {
  background: #f6f8fa; border: 1.5px solid #9aa6b1; border-radius: 4px;
  padding: 3px 8px; font-size: 10.5px; font-weight: 700; color: #141a20; white-space: nowrap;
}
.hs-tool .lnk { color: #4a6320; font-weight: 800; text-decoration: underline; white-space: nowrap; }
.hs-metrics { display: flex; gap: 3px; margin-left: auto; flex-wrap: wrap; }
.hs-metrics .m {
  background: #3a4653; border-radius: 4px; padding: 3px 8px; min-width: 60px;
}
.hs-metrics .k {
  display: block; font-size: 7.5px; font-weight: 800; letter-spacing: .09em;
  /* #c3ccd6 measured 4.17:1 on the olive fill, under AA at 7.5px */
  text-transform: uppercase; color: #d3e2b6; white-space: nowrap;
}
.hs-metrics .v {
  display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 800; color: #fff; white-space: nowrap;
}
.hs-metrics .v i { font-style: normal; font-size: 8.5px; color: #d3e2b6; }
.hs-metrics .gold { background: #4a6320; }
.hs-metrics .save .v { color: #8fe08f; }

.hs-body {
  display: grid; grid-template-columns: 158px minmax(0,1fr); gap: 1px; background: #ccd4dc;
  position: relative;
  transition: grid-template-columns .22s ease;
}
.hs-rail { background: #f2f4f7; padding: 7px 0 9px; overflow: hidden; }
.hs-burger {
  display: block; width: calc(100% - 14px);
  margin: 0 7px 8px; background: #4a6320; color: #fff;
  border: 0; border-radius: 4px;
  padding: 6px 9px; font-family: inherit; font-size: 10px; font-weight: 800;
  text-align: left; cursor: pointer;
}
.hs-burger:hover { filter: brightness(1.12); }
.hs-burger:focus-visible, .hs-restore:focus-visible { outline: 2px solid #f0b820; outline-offset: 2px; }

/* Focus Mode: the navigation slides away and the two panels take the width,
   exactly as it does in the application. */
.homewin.focus .hs-body { grid-template-columns: 0 minmax(0,1fr); }
/* A collapsed rail is still a laid-out grid item. Squeezed to 0 width its
   nav text wraps into a column ~929px tall (610px at its normal width), and
   because a grid row takes the height of its TALLEST item that stretched both
   panes to 929 against ~530px of content: the window grew 303px and opened a
   400px hole under each pane. height:0 keeps it placed (so the panes stay in
   their own column) while contributing no height. */
.homewin.focus .hs-rail {
  padding-left: 0; padding-right: 0;
  height: 0; overflow: hidden;
}
.hs-restore {
  display: none; position: absolute; left: 5px; top: 5px; z-index: 3;
  width: 26px; height: 24px; align-items: center; justify-content: center;
  background: #4a6320; color: #fff; border: 0; border-radius: 4px;
  font-size: 12px; line-height: 1; cursor: pointer;
}
.homewin.focus .hs-restore { display: flex; }
.homewin.focus .hs-pane:first-child .hs-hd { padding-left: 36px; }
/* Scoped to .hs-hd deliberately: the generic `.hs-hd span` rule outranks a bare
   .hs-chip and was painting the label dark grey on its own olive fill. */
.hs-hd .hs-chip {
  display: none; margin-left: auto;
  background: #4a6320; color: #fff; border-radius: 3px;
  padding: 2px 8px; font-size: 9px; font-weight: 800; white-space: nowrap;
}
.homewin.focus .hs-hd .hs-chip { display: inline-block; }
.homewin.focus .hs-hd .f { margin-left: 6px; }
@media (prefers-reduced-motion: reduce) { .hs-body { transition: none; } }
.hs-grp {
  padding: 8px 11px 3px; font-size: 7.5px; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: #5b6672;
}
.hs-model {
  margin: 0 7px 4px; background: #fff; border: 1.5px solid #9aa6b1; border-radius: 4px;
  padding: 5px 8px; font-size: 10px; font-weight: 700; color: #141a20;
}
.hs-item { padding: 5px 11px; font-size: 10.5px; color: #3c4753; border-left: 3px solid transparent; }
.hs-item.on { background: #e6edda; border-left-color: #4a6320; color: #2f4014; font-weight: 800; }
.hs-tour {
  margin: 10px 7px 0; border: 1.5px solid #9aa6b1; border-radius: 4px;
  padding: 6px 9px; font-size: 10px; font-weight: 700; color: #3c4753; text-align: center;
}

.hs-panes { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 1px; background: #ccd4dc; }
.hs-pane { background: #f6f8fa; min-width: 0; display: flex; flex-direction: column; }
.hs-hd {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  background: #e4e9ee; border-bottom: 1px solid #ccd4dc; padding: 6px 10px;
}
.hs-hd b { font-size: 9.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: #141a20; }
.hs-hd span { font-size: 8.5px; color: #4b5763; }
.hs-hd .f {
  margin-left: auto; background: #f6f8fa; border: 1.5px solid #9aa6b1; border-radius: 4px;
  padding: 3px 7px; font-size: 9.5px; font-weight: 700; color: #141a20; white-space: nowrap;
}
.hs-hd .f + .f { margin-left: 0; }
.hs-hd .f.go { background: #4a6320; border-color: #4a6320; color: #fff; }
.hs-sub {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: #eef1f5; border-bottom: 1px solid #ccd4dc; padding: 5px 10px; font-size: 9.5px; color: #4b5763;
}
.hs-sub .l { font-weight: 800; white-space: nowrap; }
.hs-sub .f {
  background: #fff; border: 1.5px solid #9aa6b1; border-radius: 4px; padding: 3px 7px;
  font-size: 10px; font-weight: 700; color: #141a20; white-space: nowrap;
}
.hs-sub .f.n { font-family: var(--mono); }
.hs-legend {
  background: #f6f8fa; border-bottom: 1px solid #e3e8ee; padding: 5px 10px;
  font-size: 9px; font-weight: 700; color: #4b5763;
}

.hs-tbl { width: 100%; border-collapse: collapse; }
.hs-tbl th {
  font-size: 8.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  color: #4b5763; text-align: right; padding: 5px 6px;
  border-bottom: 1px solid #ccd4dc; white-space: nowrap;
  position: sticky; top: 0; background: #e9edf1;
}
.hs-tbl th.txt, .hs-tbl td.nm { text-align: left; }
.hs-tbl td {
  padding: 3px 5px; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 10px; text-align: right; white-space: nowrap; color: #2a3320;
  border-bottom: 1px solid #eceff3;
}
/* The generic `.appwin td.nm` clamps names with `max-width:0` + ellipsis, which
   on this screen produced "Avail. Phospho…". Reset it explicitly: equal
   specificity means the property has to be overridden, not merely omitted -
   and let the name column take what it needs; .tscroll carries any overflow. */
.hs-tbl td.nm {
  font-family: var(--sans); color: #667;
  max-width: none; overflow: visible; text-overflow: clip;
}
.hs-tbl { width: 100%; min-width: max-content; }
.hs-tbl td i { font-style: normal; font-size: 8.5px; color: #6a7280; }
.hs-tbl tr.u { background: #f2f9f2; }
.hs-tbl tr.u td { color: #276221; font-weight: 700; }
.hs-tbl tr.u td.nm { color: #1e2a16; font-weight: 700; }
.hs-tbl tr.b { box-shadow: inset 3px 0 0 #b8720a; }
.hs-tbl tr.c { box-shadow: inset 3px 0 0 #b3261e; }
/* Status marks sit in a fixed slot on the left with the number right-aligned,
   exactly as the application lays the cell out, otherwise the chip's position
   follows the width of each number and the column reads as ragged. The flex
   goes on a span, never the <td>: `display:flex` on a cell drops table-cell
   layout and the browser re-wraps it in an anonymous cell. */
.hs-tbl td .vw { display: flex; align-items: center; justify-content: space-between; gap: 7px; }
.hs-tbl td .cs { flex: 0 0 14px; display: flex; align-items: center; }
.hs-tbl td .chip { margin-right: 0; }
.hs-tbl td.lk { color: #5b6672; font-weight: 800; font-size: 8.5px; }
.hs-tbl td.rd { text-align: center; }
.hs-tbl .rdp {
  background: #e6e9ee; color: #4b5763; border-radius: 3px;
  padding: 1px 6px; font-family: var(--sans); font-size: 8.5px; font-weight: 700;
}

.hs-tot {
  display: flex; align-items: center; gap: 10px;
  background: #4a6320; color: #fff; padding: 5px 10px;
  font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 10.5px; font-weight: 800;
}
.hs-tot span { font-family: var(--sans); letter-spacing: .1em; }
.hs-tot b.r { margin-left: auto; }
.hs-cost { background: #eef1f5; padding: 4px 10px 7px; }
.hs-cost div { display: flex; align-items: baseline; gap: 8px; padding: 2px 0; font-size: 10px; color: #4b5763; }
.hs-cost span { font-family: var(--sans); }
.hs-cost i { font-style: normal; font-size: 8.5px; color: #5b6672; }
.hs-cost b { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 800; color: #141a20; }
.hs-status {
  margin-top: auto; background: #d9efdd; color: #175c28;
  padding: 6px 10px; font-size: 10px; font-weight: 800;
}

/* The window reflows on ITS OWN width, not the viewport's.
   The rail is COLLAPSED, never `display:none`: a hidden grid item is not
   placed at all, which would drop the panes into the rail's own column and
   leave them zero-wide. Collapsing the track keeps placement stable and is
   what makes the Focus Mode transition possible in the first place. */
@container (max-width: 780px) {
  .hs-body { grid-template-columns: 0 minmax(0,1fr); }
  /* same trap as Focus Mode: collapsed to 0 width, the rail would set the row height */
  .hs-rail { padding-left: 0; padding-right: 0; height: 0; overflow: hidden; }
  /* the rail is already collapsed here, which is the only thing Focus Mode
     does - so its button has nothing left to do and was rendering as an 18px
     sliver with its label clipped */
  .hs-burger { display: none; }
}
/* The two panes hold 8 nowrap columns each (456px and 448px of content) and
   .hs-tbl is min-width:max-content, so nothing can absorb a shortfall - below
   a 456px pane the last column is simply cut, and at a 1024 window Cost/Bag
   was 93% gone. Two steps, sized to the measured content:
     - trim the cell padding once the window is under 1100 (8 columns x 4px
       recovers ~32px, which covers the 1093 and 1120 cases);
     - below 1040 no padding trim is enough, so the panes stack and each one
       gets the full window.
   Phone-width panning under ~620px stays as designed. */
@container (max-width: 1100px) {
  .hs-tbl th { padding: 5px 4px; }
  .hs-tbl td { padding: 3px 3px; }
}
@container (max-width: 1040px) {
  .hs-panes { grid-template-columns: minmax(0,1fr); }
}
@container (max-width: 620px) {
  .hs-user, .hs-btns { display: none; }
}
@supports not (container-type: inline-size) {
  @media (max-width: 780px) {
    .hs-body { grid-template-columns: 0 minmax(0,1fr); }
    .hs-rail { padding-left: 0; padding-right: 0; }
  }
  /* viewport equivalents of the container widths above (container = min(1180,
     vw-44) - 11), for engines with no container-query support */
  @media (max-width: 1160px) { .hs-tbl th { padding: 5px 4px; } .hs-tbl td { padding: 3px 3px; } }
  @media (max-width: 1100px) { .hs-panes { grid-template-columns: minmax(0,1fr); } }
  @media (max-width: 620px) { .hs-user, .hs-btns { display: none; } }
}

/* ---------- Sensitivity sub-tabs ---------------------------------------- */
/* The eight tools are real, so the chips are real buttons and each opens its
   own panel. Colours here are hard-coded, NOT tokens: .appwin depicts the
   product, which has no dark mode, so a token would flip with the site theme. */

.appwin-toolbar button.chip2 {
  font-family: inherit; font-size: inherit; line-height: inherit;
  /* A <button> does not inherit `color`: it defaults to the UA's `buttontext`
     system colour, which flips to white when the OS/site theme is dark and put
     white text on the light chip. Set it explicitly. */
  color: #4b5763;
  cursor: pointer;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.appwin-toolbar button.chip2:hover { border-color: #4a6320; color: #2f4014; }
.appwin-toolbar button.chip2.go:hover { color: #fff; }
.appwin-toolbar button.chip2:focus-visible { outline: 2px solid #4a6320; outline-offset: 2px; }

/* The eight tab labels are the software's own names, so "Price Ranges" or
   "Nutrient Sensitivity" mean nothing until you have used it. A line under the
   tabs says what the open tool actually does, and changes with the tab. */
.stab-cap {
  background: #f0f3ec;
  border-bottom: 1px solid #ccd4dc;
  border-left: 3px solid #4a6320;
  padding: 7px 12px;
  font-size: 11px; line-height: 1.5; color: #3d4753;
}
.stab-cap b { color: #2f4014; font-weight: 800; }

/* They were already real buttons with cursor:pointer, but the only hover cue
   was a border tint - too quiet to read as "press me" at a glance. */
.appwin-toolbar button.chip2:hover { background: #e7eddc; }
.appwin-toolbar button.chip2.go:hover { background: #4a6320; }

.stab { display: none; }
.stab.on { display: block; }

.appwin td.good { color: #175c28; font-weight: 800; }

.appwin-note {
  border-top: 1px solid #ccd4dc; background: #eef1f5;
  padding: 10px 13px; font-size: 11px; color: #4b5763; line-height: 1.55;
  font-family: var(--sans);
}
.appwin-note b { color: #141a20; font-weight: 800; }

/* control strip: the pickers and buttons the real screens carry */
.sc-ctl {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: #eef1f5; border-bottom: 1px solid #ccd4dc;
  padding: 9px 13px;
  font-family: var(--sans); font-size: 10.5px;
}
.sc-ctl .l { font-weight: 800; color: #4b5763; white-space: nowrap; }
.sc-ctl .f {
  background: #f6f8fa; border: 1.5px solid #9aa6b1; border-radius: 4px;
  padding: 4px 9px; font-size: 11px; font-weight: 700; color: #141a20;
}
.sc-ctl .f.n { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.sc-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: #ccd4dc; }
.sc-card { background: #f6f8fa; padding: 11px 13px; min-width: 0; border-top: 3px solid #9aa6b1; }
.sc-card.up { border-top-color: #b3261e; }
.sc-card.dn { border-top-color: #1f7a34; }
.sc-card .k { font-size: 9px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: #4b5763; }
.sc-card .v {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 20px; font-weight: 800; color: #141a20; margin-top: 3px;
}
.sc-card .v small { font-size: 10.5px; font-weight: 600; color: #4b5763; }
.sc-card .d { font-family: var(--mono); font-size: 12px; font-weight: 800; margin-top: 3px; }
.sc-card .d.up { color: #971f14; }
.sc-card .d.dn { color: #175c28; }
.sc-card .s { font-size: 10.5px; color: #4b5763; margin-top: 5px; line-height: 1.5; }
.sc-card .chip2 { margin-top: 9px; }

/* the empty state between picking and calculating - the panel must not look
   broken while it is waiting for you to press the button */
.sc-empty {
  grid-column: 1 / -1; background: #f6f8fa;
  padding: 18px 13px; text-align: center;
  font-family: var(--sans); font-size: 11px; color: #4b5763;
}
.sc-empty b { color: #2f4014; font-weight: 800; }

/* a card whose change has been applied */
.sc-card.applied { background: #eef4e6; }
.sc-done {
  margin-top: 9px; font-family: var(--sans); font-size: 10.5px;
  font-weight: 800; color: #175c28;
}

/* the notification list on the Inventory Analytics view */
.alerts { padding: 4px 0; }
.al {
  padding: 7px 13px; border-bottom: 1px solid #e3e8ee;
  font-family: var(--sans); font-size: 10.5px; line-height: 1.5; color: #3d4753;
  border-left: 3px solid #9aa6b1;
}
.al:last-child { border-bottom: 0; }
.al b { font-weight: 800; color: #141a20; }
.al.crit { border-left-color: #b3261e; background: #fdf1f1; }
.al.crit b { color: #971f14; }
.al.warn { border-left-color: #b8720a; background: #fdf8ee; }
.al.warn b { color: #7d4e06; }
.al.ok   { border-left-color: #1f7a34; background: #f2f9f2; }
.al.ok b { color: #175c28; }

/* what an action that leaves the page actually does in the program */
.say-note {
  background: #eef4e6; border-top: 1px solid #ccd4dc; border-left: 3px solid #4a6320;
  padding: 7px 12px;
  font-family: var(--sans); font-size: 10.5px; line-height: 1.5; color: #3d4753;
}
.say-note b { color: #2f4014; font-weight: 800; }

/* the honest-failure tag on Cost Optimize */
.co-tag.bad { background: #f7dedb; color: #971f14; }

/* what Print / CSV do in the program */
.out-note {
  margin-top: 7px; padding: 6px 8px;
  background: #eef4e6; border-left: 3px solid #4a6320;
  font-family: var(--sans); font-size: 10px; line-height: 1.5; color: #3d4753;
}

/* These are real controls now, so they have to be tappable: WCAG 2.5.8 asks
   for 24x24 CSS px and they were rendering at 20-22px. inline-flex keeps the
   label centred once a min-height is forced on them. */
button.chip2, button.f, .catdlg-btn {
  min-height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
}

/* the two cycling fields are buttons now, so they need the press affordance */
.sc-ctl button.f { cursor: pointer; font-family: var(--sans); }
.sc-ctl button.f.n { font-family: var(--mono); }
.sc-ctl button.f:hover { border-color: #4a6320; background: #fff; }
.sc-ctl button.f:focus-visible { outline: 2px solid #4a6320; outline-offset: 2px; }

.co-list { padding: 4px 0; }
.co-item {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 9px 13px; border-bottom: 1px solid #e3e8ee;
  font-family: var(--sans);
}
.co-item:last-child { border-bottom: 0; }
.co-item > div { min-width: 0; }
.co-item b { display: block; font-size: 12px; font-weight: 700; color: #141a20; }
.co-item span { display: block; font-size: 10.5px; color: #4b5763; line-height: 1.55; margin-top: 2px; }
.co-item span b { display: inline; font-size: inherit; }
.co-tag {
  flex: 0 0 auto; margin-top: 1px;
  font-size: 8.5px; font-weight: 800; letter-spacing: .07em;
  padding: 3px 6px; border-radius: 3px; white-space: nowrap;
}
.co-tag.ok   { background: #d9efdd; color: #175c28; }
.co-tag.warn { background: #f8efd8; color: #7d4e06; }
.co-tag.crit { background: #f7dedb; color: #971f14; }
.co-item.co-none { background: #fdf4f3; }
.sc-card.na { border-top-color: #b3261e; }
.sc-card .v.na { font-family: var(--sans); font-size: 15px; color: #971f14; }
.sc-ctl button.chip2 { cursor: pointer; }

/* the 01 / 02 rule above each cost-tool heading */
.feat-num {
  font-family: var(--mono); font-size: 12px; font-weight: 800;
  letter-spacing: .16em; color: var(--accent);
  padding-bottom: 8px; margin-bottom: 12px;
  border-bottom: 2px solid var(--accent);
  display: inline-block;
}

@media (max-width: 700px) {
  .sc-cards { grid-template-columns: 1fr; }
}

.barcell { display: flex; align-items: center; gap: 7px; justify-content: flex-end; }
.bar { height: 6px; border-radius: 2px; background: #dde3ea; flex: 0 0 62px; overflow: hidden; }
.bar i { display: block; height: 100%; background: #4a6320; }
.bar i.warn { background: #b8720a; } .bar i.crit { background: #b3261e; }

/* two-pane split inside a screen */
.appwin-split { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: #ccd4dc; }
.appwin-split > div { background: #f6f8fa; min-width: 0; }
@container (max-width: 620px) { .appwin-split { grid-template-columns: 1fr; } }

/* On a phone these are dense application tables in ~350px. Rather than shrink
   them into illegibility, each table pans inside its own scroller: the same
   pattern the comparison table uses. The page itself never scrolls sideways. */
.tscroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tscroll::-webkit-scrollbar { height: 6px; }
.tscroll::-webkit-scrollbar-thumb { background: #ccd4dc; border-radius: 3px; }

@container (max-width: 620px) {
  /* was a flat min-width:520px. The container here is the PANEL, and a panel in
     a two-column section is ~504px on a full desktop - so this phone rule fired
     at 1440 and forced a 520px table into a 501px box, permanently cutting the
     last column in half. max-content asks each table what it actually needs
     (the database table: 401px), so it fills the panel on a desktop and still
     pans on a phone instead of squashing. */
  .appwin table { min-width: max-content; }
  .appwin .appwin-split table { min-width: 300px; }
}

/* ---------- 17. Motion --------------------------------------------------- */

/* Reveal-on-scroll. The .in class is added by JS, so hiding these
   unconditionally meant that with scripts unavailable the whole page rendered
   INVISIBLE, which is exactly what an iOS Files/Quick Look preview does.
   Hidden only under .js (set by an inline script in <head> before paint), so
   no-JS gets the content plainly and scripted browsers still get the reveal. */
.rv { transition: opacity 520ms ease, transform 520ms cubic-bezier(.2,.7,.3,1); }
.js .rv { opacity: 0; transform: translateY(14px); }
.js .rv.in, .rv.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
  .rv { opacity: 1; transform: none; }
  /* the depth stays, it is composition, not motion, but it stops moving */
  .scene:hover .tilt3d, .hero .scene:hover .tilt3d { transform: none; }
}

/* ---------- 18. Utilities ------------------------------------------------ */

.mt0 { margin-top: 0; }
.mt-s { margin-top: 14px; }
.mt-m { margin-top: 26px; }
.mt-l { margin-top: 40px; }
.center { text-align: center; }
.center .lead, .center .sec-head { margin-left: auto; margin-right: auto; }
.center .eyebrow { justify-content: center; }
.vh {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- 19. Touch targets -------------------------------------------
   Every interactive element gets a comfortable hit area. Audited on a 360px
   viewport: the logo link, the unit toggle, the range slider and the footer
   links all came in under 36px before these rules.                        */

.brand { padding: 9px 0; }                 /* 26px logo -> 44px hit area */

.foot-links a { display: inline-block; padding: 10px 0; }

.faq summary { min-height: 44px; }

@media (max-width: 620px) {
  .icon-btn { width: 42px; height: 42px; }
  .btn { padding: 14px 22px; }          /* ~48px tall on phones */
  .contact-list a, .contact-list span { padding: 4px 0; display: inline-block; }
  .mock-solve { min-height: 42px; padding: 9px 20px; }
}

/* ============================================================================
   18. Datasheet pass
   The page had drifted into the shape every generated marketing site takes:
   soft rounded cards in even 3-across grids, a stroke icon in a rounded square
   above each one, an identical eyebrow/headline/lead stack opening every
   section, and symmetric 50/50 splits throughout.

   This pass pulls it back to the register the brand actually specifies -
   "flat surfaces, structural borders, monospaced numerics": by borrowing from
   a technical datasheet: square geometry, ruled plates instead of boxes,
   hanging monospace ordinals, and deliberately uneven columns. It is a restyle
   only; no markup structure, copy or behaviour depends on it.
   ========================================================================== */

:root { --radius: 2px; }

/* --- square the geometry ------------------------------------------------- */
.btn, .icon-btn, .cta-box, .stat-strip, .cmp-wrap, .appwin, .mock,
.faq details, .portrait, .contact-list, .showcase-tabs button { border-radius: 2px; }
.appwin, .mock { border-radius: 0; }
.tilt3d::after { border-radius: 0; }
.soft3d.flipped .tilt3d::after { border-radius: 0; }

/* --- sections become numbered, ruled plates ------------------------------ */
/* The repeated eyebrow → headline → lead stack is the single most recognisable
   generated-page rhythm. A hanging section number and a rule across the top
   turn it into a document instead. */
main { counter-reset: ffsec; }
main > section.band { counter-increment: ffsec; }

.sec-head {
  max-width: none;
  border-top: 2px solid var(--ink);
  padding-top: 18px;
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  column-gap: 26px;
}
.sec-head > * { grid-column: 2; }
.sec-head::before {
  content: counter(ffsec, decimal-leading-zero);
  grid-column: 1; grid-row: 1 / span 99;
  font-family: var(--mono);
  font-size: 32px; font-weight: 700; line-height: .82;
  letter-spacing: -.04em;
  /* 32px counts as large text, so 3:1 is the floor. var(--rail) measured
     2.42:1 on the light surface, legible enough to read as a mark, not
     enough to read as a number. */
  color: #7f8b6a;
}
.band-dark .sec-head { border-top-color: var(--chrome-ink2); }
/* --chrome-line measured 1.31:1 on the dark plate, effectively invisible */
.band-dark .sec-head::before { color: #86976a; }
.sec-head .lead { max-width: 58ch; }

/* the eyebrow drops its amber dash and becomes a monospace file label */
.eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .24em;
  color: var(--ink3);
  margin-bottom: 11px;
}
.eyebrow::before { display: none; }
.band-dark .eyebrow { color: var(--chrome-ink2); }

/* --- headlines: tighter, no trailing full stop --------------------------- */
h2.hh { letter-spacing: -.032em; line-height: 1.04; }
h3.hs { letter-spacing: -.022em; }

/* --- cards become ruled index entries ------------------------------------ */
/* No box, no icon tile, no left accent bar. A rule, a hanging ordinal, and the
   text, which is what a parts index or a specification sheet looks like. */
.grid { counter-reset: ffcard; gap: 24px 30px; }
.card {
  counter-increment: ffcard;
  background: transparent;
  border: 0;
  border-top: 2px solid var(--line);
  border-radius: 0;
  padding: 14px 0 6px;
}
.card:hover { border-top-color: var(--accent); background: transparent; }
.card h3 { font-size: 15.5px; letter-spacing: -.015em; margin-bottom: 7px; }
.card h3::before {
  content: counter(ffcard, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .06em;
  color: var(--rail);
  margin-right: 10px;
}
.card-ic { display: none; }
.band-dark .card {
  background: transparent;
  border: 0; border-top: 2px solid var(--chrome-line);
}
.band-dark .card:hover { border-top-color: var(--amber); background: transparent; }
.band-dark .card h3::before { color: var(--chrome-line); }
/* the two callout cards carry their own accent and keep a surface */
.card[style*="--amber"] {
  background: var(--panel);
  border-top: 2px solid var(--amber);
  padding: 18px;
}
.band-dark .card[style*="--amber"] { background: rgba(255,255,255,.04); }
.card[style*="--amber"] h3::before,
.card[style*="--amber"] .eyebrow::before { content: none; }

/* the capability columns get the same rule treatment, without ordinals */
.cap-col h3 { letter-spacing: .14em; }

/* --- deliberately uneven splits ------------------------------------------ */
/* A 50/50 split reads as a template. Text and instrument are not equal weight. */
@media (min-width: 901px) {
  .split { grid-template-columns: minmax(0, 1.06fr) minmax(0, .94fr); }
  .split.flip { grid-template-columns: minmax(0, .94fr) minmax(0, 1.06fr); }
}

/* --- buttons: blocks, not pills ------------------------------------------ */
.btn {
  letter-spacing: .06em;
  text-transform: uppercase;
  font-size: 12.5px;
}
.btn-primary { border-radius: 2px; }

/* --- a hairline between bands, so they stack like plates ----------------- */
.band + .band { border-top: 1px solid var(--line); }
.band-dark + .band-dark { border-top-color: var(--chrome-line); }

@media (max-width: 700px) {
  .sec-head { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
  .sec-head::before { grid-column: 1; grid-row: auto; font-size: 22px; margin-bottom: 10px; }
  .sec-head > * { grid-column: 1; }
}

/* --- highlight: "you are only seeing a few things here" -------------------- */
/* Sits under the screen showcase, where a visitor has just formed a view of how
   big the program is from eight pictures. Deliberately the loudest block on the
   page after the hero: amber rule, amber flag, oversized opening line. */
.more-note {
  position: relative;
  margin-top: clamp(34px, 4.5vw, 54px);
  background: rgba(240, 184, 32, .07);
  border: 1px solid var(--chrome-line);
  border-top: 4px solid var(--amber);
  padding: clamp(24px, 3vw, 34px) clamp(22px, 3vw, 36px);
  max-width: none;
  font-size: clamp(15px, 1.6vw, 16.5px);
  line-height: 1.62;
  color: var(--chrome-ink);
}
.more-note::before {
  content: "Please note";
  position: absolute; top: -4px; left: clamp(22px, 3vw, 36px);
  transform: translateY(-50%);
  background: var(--amber); color: #1c2109;
  font-family: var(--mono);
  font-size: 10px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;
  padding: 4px 10px;
}
.more-note span {
  display: block;
  font-size: clamp(21px, 2.7vw, 30px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.1;
  color: #fff;
  margin-bottom: 12px;
  max-width: 22ch;
}
.more-note b { color: #fff; font-weight: 700; }
.more-note a { color: var(--amber); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.more-note a:hover { color: #fff; }
@media (max-width: 700px) { .more-note span { max-width: none; } }

/* --- the batch as a 3D object -------------------------------------------- */
/* The scene and the numbers are one component: the table is the source of
   truth and stays put if WebGL is unavailable, the canvas illustrates it. */

.batch-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(26px, 4vw, 54px);
  align-items: center;
}
.batch-view { position: relative; min-width: 0; }
#ff-batch {
  display: block;
  width: 100%;
  height: clamp(320px, 42vw, 470px);
  touch-action: pan-y;              /* vertical scroll still works over it */
  cursor: grab;
}
#ff-batch:active { cursor: grabbing; }
.batch-hint {
  font-size: 12px;
  color: var(--ink3);
  margin-top: 10px;
  max-width: 46ch;
}

.batch-data { min-width: 0; }
.batch-tbl { width: 100%; border-collapse: collapse; }
.batch-tbl thead th {
  font-family: var(--mono);
  font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink3); text-align: right;
  padding: 0 8px 9px; border-bottom: 2px solid var(--ink);
}
.batch-tbl thead th.txt { text-align: left; }
.batch-tbl td {
  padding: 7px 8px;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 13px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid var(--line);
  color: var(--ink2);
}
.batch-tbl td.txt {
  font-family: var(--sans); text-align: left; color: var(--ink); font-weight: 600;
  white-space: normal;
}
.batch-tbl td.sw { width: 20px; padding-right: 0; }
.batch-tbl td.sw i {
  display: block; width: 11px; height: 11px; border-radius: 2px;
  border: 1px solid rgba(0,0,0,.22);
}
.batch-tbl tbody tr { transition: background var(--t); }
.batch-tbl tbody tr[data-i]:hover,
.batch-tbl tbody tr[data-i].lit { background: var(--accent-soft); cursor: default; }
.batch-tbl tr.tot td {
  border-bottom: 0; border-top: 2px solid var(--ink);
  color: var(--ink); font-weight: 800;
}
.batch-tbl tr.tot td.txt { font-weight: 800; }

/* screen-reader-only caption */
.np-sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

@media (max-width: 900px) {
  .batch-wrap { grid-template-columns: minmax(0, 1fr); }
  #ff-batch { height: clamp(280px, 62vw, 380px); }
}

/* --- batch scene: dataset switch, cost readout ---------------------------- */
.batch-ctl { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.batch-ctl button {
  font-family: var(--mono);
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  background: transparent; color: var(--ink2);
  border: 1.5px solid var(--rail); border-radius: 2px;
  padding: 7px 12px; cursor: pointer;
  transition: background var(--t), color var(--t), border-color var(--t);
}
.batch-ctl button:hover { border-color: var(--action); color: var(--ink); }
.batch-ctl button.on {
  background: var(--action); border-color: var(--action); color: var(--on-action);
}
.batch-ctl button:focus-visible { outline: 3px solid var(--amber); outline-offset: 2px; }

.batch-cost {
  display: flex; align-items: baseline; gap: 12px;
  margin-top: 14px; padding-top: 12px;
  border-top: 2px solid var(--ink);
}
.batch-cost span {
  font-family: var(--mono);
  font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink3);
}
.batch-cost b {
  margin-left: auto;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: clamp(22px, 2.6vw, 28px); font-weight: 800;
  letter-spacing: -.02em; color: var(--deep);
}
.batch-note {
  margin-top: 9px;
  font-size: 12.5px; line-height: 1.55; color: var(--ink2);
  min-height: 3em;                       /* no reflow when the wording changes */
}
.batch-note b { color: var(--deep); font-weight: 800; }

/* --- nav: nine links have to hold one row --------------------------------- */
/* Adding a ninth link put the content at exactly the nav's width, so it
   wrapped to two rows. The links were inheriting the 16px body size, which is
   larger than a nav needs; 14.5px restores real slack instead of costing a
   section its link. */
/* multi-word labels were wrapping INSIDE their own box: each rendered on
   two lines, which is what made the bar look like it had two rows. */
.nav a { font-size: 14.5px; white-space: nowrap; }
@media (min-width: 981px) { .nav { gap: 2px; } }

/* ============================================================================
   19. The 3D stage
   Taken from the reference the client pointed at: a near-black green ground,
   large light-weight type on wide tracking, and depth built from LAYERS moving
   at different rates rather than from a 3D library. That site uses luxy.js for
   the parallax; this uses native scroll-driven animation, so it costs nothing
   and cannot jank. Applied to the 3D section only: the rest of the page is a
   datasheet and stays one.
   ========================================================================== */

.batch-stage {
  position: relative;
  overflow: hidden;
  background: #000f08;                       /* the reference's ground tone */
  border-top: 1px solid #05200f;
  border-bottom: 1px solid #05200f;
}
/* key light behind the object, so it sits IN the dark rather than on it */
.batch-stage .stage-glow {
  position: absolute; pointer-events: none;
  left: 8%; top: 18%; width: 46%; height: 78%;
  background: radial-gradient(ellipse at 50% 45%,
              rgba(150, 190, 90, .17), rgba(120, 160, 70, .07) 42%, transparent 70%);
  filter: blur(6px);
  z-index: 0;
}
/* a far horizon grid: the deepest layer, and the one that moves least */
.batch-stage .stage-grid {
  position: absolute; inset: -10% -5%;
  pointer-events: none; z-index: 0;
  background-image:
    linear-gradient(rgba(160, 200, 120, .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(160, 200, 120, .05) 1px, transparent 1px);
  background-size: 92px 92px;
  mask-image: radial-gradient(ellipse at 50% 40%, #000 20%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse at 50% 40%, #000 20%, transparent 72%);
}
.batch-stage > .wrap { position: relative; z-index: 1; }

/* type: lighter, larger, tracked wide, the reference's display voice */
.batch-stage .sec-head { border-top-color: rgba(190, 214, 160, .45); }
.batch-stage .sec-head::before { color: #4f6b3c; }
.batch-stage .eyebrow { color: #93ab77; letter-spacing: .34em; }
.batch-stage h2.hh {
  font-weight: 300;
  letter-spacing: .02em;
  line-height: 1.08;
  color: #f2f7ea;
}
.batch-stage .lead { color: #b7c8a2; }

/* the table, restated for the dark stage */
.batch-stage .batch-tbl thead th { color: #8fa677; border-bottom-color: rgba(190, 214, 160, .5); }
.batch-stage .batch-tbl td { color: #c2d2ae; border-bottom-color: rgba(190, 214, 160, .16); }
.batch-stage .batch-tbl td.txt { color: #f2f7ea; }
.batch-stage .batch-tbl tbody tr[data-i]:hover,
.batch-stage .batch-tbl tbody tr[data-i].lit { background: rgba(150, 190, 90, .14); }
.batch-stage .batch-tbl tr.tot td { border-top-color: rgba(190, 214, 160, .55); color: #fff; }
.batch-stage .batch-cost { border-top-color: rgba(190, 214, 160, .55); }
.batch-stage .batch-cost span { color: #8fa677; }
.batch-stage .batch-cost b { color: #d6e8b4; }
.batch-stage .batch-note { color: #b7c8a2; }
.batch-stage .batch-note b { color: #d6e8b4; }
.batch-stage .batch-hint { color: #8fa677; }
.batch-stage .batch-ctl button { color: #b7c8a2; border-color: #3d5230; }
.batch-stage .batch-ctl button:hover { color: #fff; border-color: #7d9a5c; }
.batch-stage .batch-ctl button.on { background: #4a6320; border-color: #6f9139; color: #fff; }
.batch-stage .batch-tbl td.sw i { border-color: rgba(255,255,255,.25); }

/* --- the parallax: three planes, three rates ----------------------------- */
@supports (animation-timeline: view()) {
  @media (min-width: 901px) and (prefers-reduced-motion: no-preference) {
    .batch-stage .stage-grid,
    .batch-stage .stage-glow,
    .batch-stage .batch-view,
    .batch-stage .batch-data {
      animation: linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    /* furthest back, barely moves */
    .batch-stage .stage-grid { animation-name: ff-par-far; }
    .batch-stage .stage-glow { animation-name: ff-par-glow; }
    /* the object rides mid-depth, the numbers sit closest and move most */
    .batch-stage .batch-view { animation-name: ff-par-mid; }
    .batch-stage .batch-data { animation-name: ff-par-near; }

    @keyframes ff-par-far  { from { transform: translate3d(0,  26px, 0); }
                             to   { transform: translate3d(0, -26px, 0); } }
    @keyframes ff-par-glow { from { transform: translate3d(0,  44px, 0); opacity: .55; }
                             50%  { opacity: 1; }
                             to   { transform: translate3d(0, -44px, 0); opacity: .55; } }
    @keyframes ff-par-mid  { from { transform: translate3d(0,  54px, 0); }
                             to   { transform: translate3d(0, -34px, 0); } }
    @keyframes ff-par-near { from { transform: translate3d(0,  88px, 0); }
                             to   { transform: translate3d(0, -56px, 0); } }
  }
}

/* --- the F mark on the hero and the 3D stage ----------------------------- */
/* Every band gets it through .wm, but the hero is not a .band and its
   ::before already draws the engineering grid, so the mark goes on ::after.
   The stage is near-black, so its copy is brightened and pushed to the far
   side, clear of the object. */
.hero::after {
  content: "";
  position: absolute;
  /* LEFT, not right: the right half of the hero is the app window, which is
     opaque and hid the mark completely. */
  left: -90px; top: 50%;
  width: min(560px, 48vw); aspect-ratio: 164 / 159;
  transform: translateY(-50%);
  background: url(assets/f-mark.svg) center / contain no-repeat;
  opacity: .075;
  pointer-events: none;
  z-index: 0;                 /* above the grid, below .wrap (z-index 1) */
}
.batch-stage.wm::before { opacity: .05; right: -90px; }

@media (max-width: 760px) {
  .hero::after { width: 72vw; right: -24vw; opacity: .045; }
}

/* ============================================================================
   20. Header: grouped nav, condense-on-scroll, full-screen mobile menu
   Merged from the standalone header mock. Two changes were made deliberately
   during the merge:
     · No Google Fonts. The mock imported Fraunces + Inter; this page loads
       nothing from the network and the wordmark is already in the logo SVG.
     · Its parallel palette (--forest/--gold/--cream) is dropped for the tokens
       already in this stylesheet, so the header cannot drift from the page.
   ========================================================================== */

.site-head {
  backdrop-filter: blur(10px);
  transition: box-shadow .35s var(--t-ease, cubic-bezier(.22,.61,.36,1));
}
/* the gold hairline from the mock, over the existing 2px amber rule */
.site-head::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: linear-gradient(90deg, transparent, var(--amber) 18%, var(--amber-deep) 82%, transparent);
  pointer-events: none;
}
.site-head.scrolled { box-shadow: 0 8px 30px rgba(0,0,0,.28); }
.head-in { transition: height .35s cubic-bezier(.22,.61,.36,1); }
.site-head.scrolled .head-in { height: 84px; }
.site-head.scrolled .brand img { height: 66px; }
.brand img { transition: height .35s cubic-bezier(.22,.61,.36,1); }

/* "try it" invitation above the screen showcase. The panels are genuinely
   interactive, but they look like screenshots, so nobody presses them unless
   told to. */
.try-note {
  margin-top: 14px; max-width: 74ch;
  padding: 10px 14px;
  background: rgba(240,184,32,.10);
  border-left: 3px solid var(--amber);
  border-radius: 0 4px 4px 0;
  font-size: 14px; line-height: 1.6; color: #e6ead8;
}
.try-note b { color: #fff; font-weight: 800; }

/* Currency picker. The software asks which currency you work in and then uses
   it everywhere; the site claims that, so it demonstrates it. Changing it
   rewrites every currency mark on the page - the AMOUNTS never move, because
   there is no exchange rate here and none in the product either. */
.ccy-pick { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.ccy-lbl {
  font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--chrome-ink2); white-space: nowrap;
}
.ccy-pick select {
  font-family: inherit; font-size: 12px; font-weight: 700;
  color: #fff; background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.22); border-radius: 4px;
  padding: 5px 7px; min-height: 30px; max-width: 132px; cursor: pointer;
}
.ccy-pick select:hover { background: rgba(255,255,255,.14); }
.ccy-pick select:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
/* the options render on the OS menu, which is light on Windows */
.ccy-pick option { color: #141a20; background: #fff; }
@media (max-width: 1180px) { .ccy-lbl { display: none; } }
/* keep it on phones - a mobile visitor needs it as much as anyone; just
   narrow it so the OS truncates the option text rather than the header */
/* On a phone only the symbol needs to be legible - the label ellipsises.
   Both the enhanced button AND the native select are sized, because the
   native one is what shows if the enhancer never runs. */
@media (max-width: 900px) {
  .ccy-pick { gap: 0; }
  .ccy-pick select { max-width: 64px; padding: 5px 2px; font-size: 11px; }
  .ccy-pick .cs-wrap { max-width: 64px; }
  .ccy-pick .cs-btn { max-width: 64px; padding: 5px 5px; font-size: 11px; gap: 4px; }
}

/* --- grouped nav --------------------------------------------------------- */
.nav-item { position: relative; }
.nav-link, .nav-trigger {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 11px; height: 39px; border-radius: 4px;   /* buttons and links
     measured 34px vs 39px, so the hover fills were different sizes */
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  color: var(--chrome-ink2); background: none; border: 0;
  cursor: pointer; white-space: nowrap;
  transition: color var(--t), background var(--t);
}
.nav-link:hover, .nav-trigger:hover,
.nav-item[data-open="true"] .nav-trigger { color: #fff; background: rgba(255,255,255,.08); }
.nav-trigger .chev { width: 11px; height: 11px; opacity: .75; transition: transform .3s cubic-bezier(.22,.61,.36,1); }
.nav-item[data-open="true"] .chev { transform: rotate(180deg); }

.dropdown {
  position: absolute; top: calc(100% + 12px); left: 0;
  min-width: 300px; padding: 6px;
  background: var(--chrome-a);
  border: 1px solid var(--chrome-line); border-radius: 4px;
  box-shadow: 0 24px 48px rgba(0,0,0,.42);
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: opacity .22s cubic-bezier(.22,.61,.36,1),
              transform .22s cubic-bezier(.22,.61,.36,1), visibility .22s;
  z-index: 5;
}
.nav-item[data-open="true"] .dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
/* bridges the gap so the panel does not close as the pointer travels to it */
.dropdown::before { content: ""; position: absolute; top: -12px; left: 0; right: 0; height: 12px; }
.drop-link {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 11px; border-radius: 3px;
  transition: background .18s cubic-bezier(.22,.61,.36,1);
}
.drop-link:hover { background: rgba(240,184,32,.10); }
.drop-link .t { font-size: 13.5px; font-weight: 700; color: var(--chrome-ink); }
.drop-link:hover .t { color: var(--amber); }
.drop-link .d { font-size: 11.5px; line-height: 1.4; color: var(--chrome-ink2); }

/* --- full-screen mobile menu --------------------------------------------- */
.mobile-menu {
  position: fixed; inset: 0; z-index: 90;
  background: var(--chrome-a);
  padding: 110px clamp(16px, 5vw, 40px) 40px;
  display: none; flex-direction: column; gap: 2px;
  transform: translateX(100%);
  transition: transform .4s cubic-bezier(.22,.61,.36,1);
  overflow-y: auto;
}
body.menu-open .mobile-menu { transform: translateX(0); }
.m-group { border-bottom: 1px solid var(--chrome-line); }
.m-group > button {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding: 16px 3px; font-family: inherit; font-size: 17px; font-weight: 700;
  color: var(--chrome-ink); background: none; border: 0; cursor: pointer;
}
.m-group > button .chev { width: 14px; height: 14px; transition: transform .3s cubic-bezier(.22,.61,.36,1); }
.m-group[data-open="true"] > button .chev { transform: rotate(180deg); }
.m-panel { max-height: 0; overflow: hidden; transition: max-height .35s cubic-bezier(.22,.61,.36,1); }
.m-panel-inner { padding: 0 3px 14px; }
.m-panel a { display: block; padding: 10px 0; font-size: 15px; color: var(--chrome-ink2); text-decoration: none; }
.m-panel a:hover { color: var(--amber); }
.m-flat {
  padding: 16px 3px; font-size: 17px; font-weight: 700;
  color: var(--chrome-ink); text-decoration: none;
  border-bottom: 1px solid var(--chrome-line);
}
.m-cta { margin-top: 26px; justify-content: center; padding: 15px; font-size: 15px; }

@media (max-width: 940px) {
  .nav { display: none; }
  .burger { display: inline-flex; }
  .mobile-menu { display: flex; }
  .head-cta .btn-label { display: none; }
}
@media (max-width: 560px) {
  .head-cta .btn-primary { display: none; }
  .brand img { height: 64px; }
  .head-in { height: 84px; }
  .mobile-menu { padding-top: 92px; }
}
@media (prefers-reduced-motion: reduce) {
  .site-head, .head-in, .brand img, .dropdown, .mobile-menu, .m-panel, .chev { transition: none; }
}

/* ============================================================================
   21. Custom select
   The native <select> is kept for semantics, keyboard support and form value
   but visually removed; a styled button and a fixed-position listbox stand in
   for it, so the control matches the rest of the page.

   Only the app's `--ff-*` tokens are remapped to this stylesheet's; the
   geometry, weights and interaction are unchanged. The app's per-control width
   pins (#inv-sort, #basis-select …) are app-only and are not carried over.
   ========================================================================== */

.cs-wrap { position: relative; display: inline-block; vertical-align: middle; max-width: 100%; }
.cs-wrap.cs-full { display: block; width: 100%; }
/* kept in the DOM so the form value and label association survive */
.cs-native {
  position: absolute !important; width: 1px; height: 1px;
  opacity: 0; pointer-events: none; overflow: hidden; clip: rect(0 0 0 0);
}
.cs-btn {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 6px 10px;
  background: var(--surface); border: 1.5px solid var(--rail); border-radius: 6px;
  font-family: inherit; font-size: 13px; font-weight: 600; color: var(--ink);
  cursor: pointer; line-height: 1.3; min-height: 30px;
}
.cs-btn:hover { border-color: var(--accent); }
.cs-btn[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.cs-btn .cs-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
.cs-chev {
  flex: none; width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid currentColor; opacity: .5; transition: transform .15s;
}
.cs-btn[aria-expanded="true"] .cs-chev { transform: rotate(180deg); }
/* position:fixed so the list is never clipped by a panel's overflow */
.cs-menu {
  position: fixed; z-index: 9500;
  width: max-content; max-width: min(440px, 92vw); max-height: 340px;
  overflow-y: auto; overflow-x: hidden;
  background: var(--surface); border: 1.5px solid var(--rail); border-radius: 8px;
  box-shadow: 0 14px 36px rgba(20,26,32,.24);
  padding: 4px; display: none;
}
.cs-menu.open { display: block; }
.cs-opt {
  padding: 8px 10px; border-radius: 5px; cursor: pointer;
  font-size: 13px; color: var(--ink); white-space: nowrap;
  display: flex; align-items: center; gap: 8px;
}
.cs-opt:hover { background: var(--accent-soft); }
.cs-opt.sel { font-weight: 700; }
.cs-opt.sel::after { content: "\2713"; margin-left: auto; color: var(--accent); font-weight: 800; }
/* optgroups render as a clickable header over a collapsible body */
.cs-grp {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 10px 6px; margin-top: 2px; border-radius: 5px; cursor: pointer;
  font-size: 12px; font-weight: 800; color: #2f4210; background: var(--accent-soft);
  white-space: nowrap; user-select: none;
}
.cs-grp:hover { background: #dfe8cd; }
.cs-grp .cs-grp-chev { flex: none; width: 10px; font-size: 9px; color: var(--accent); }
.cs-grp .cs-grp-n { margin-left: auto; font-size: 10px; font-weight: 700; color: var(--ink3); }
.cs-grp-body .cs-opt { padding-left: 26px; }

/* the site has dark bands; the product does not, so this part is site-only */
.band-dark .cs-btn, .hero .cs-btn {
  background: rgba(255,255,255,.06); border-color: var(--chrome-line); color: var(--chrome-ink);
}
.band-dark .cs-btn:hover, .hero .cs-btn:hover { border-color: var(--amber); }

/* the currency picker in the header uses the product's own dropdown, so it
   has to read on the dark chrome rather than on an app surface */
.ccy-pick .cs-wrap { width: 100%; }
.ccy-pick .cs-btn {
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.22);
  border-radius: 4px;
  color: #fff; font-size: 12px; font-weight: 700;
  padding: 5px 8px; min-height: 30px;
}
.ccy-pick .cs-btn:hover { background: rgba(255,255,255,.14); border-color: var(--amber); }
.ccy-pick .cs-btn[aria-expanded="true"] {
  border-color: var(--amber); box-shadow: 0 0 0 2px rgba(240,184,32,.35);
}
.ccy-pick .cs-chev { opacity: .85; }

/* --- the same control, adapted per device -------------------------------- */
/* Coarse pointers get 44px targets; a phone gets the list as a bottom sheet,
   because a fixed panel anchored to a button is unusable at 375px. */
@media (pointer: coarse) {
  .cs-btn { min-height: 44px; padding: 10px 12px; font-size: 15px; }
  .cs-opt { padding: 13px 12px; font-size: 15px; }
  .cs-grp { padding: 11px 12px; font-size: 13px; }
}
@media (max-width: 560px) {
  .cs-menu.open {
    position: fixed;
    left: 0 !important; right: 0;
    top: auto !important; bottom: 0;
    width: 100%; max-width: 100%; min-width: 0 !important;
    max-height: 62vh;
    border-radius: 12px 12px 0 0;
    border-bottom: 0;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -14px 44px rgba(20,26,32,.34);
    animation: cs-sheet .22s cubic-bezier(.22,.61,.36,1);
  }
  @keyframes cs-sheet { from { transform: translateY(14%); opacity: .6 } to { transform: none; opacity: 1 } }
  /* a sheet needs something to dismiss against */
  .cs-backdrop {
    position: fixed; inset: 0; z-index: 9499;
    background: rgba(10,15,8,.42);
  }
}
/* the backdrop only exists for the sheet presentation */
.cs-backdrop { display: none; }
@media (max-width: 560px) { .cs-backdrop.on { display: block; } }

/* --- founder: contact details under the signature ------------------------ */
.sig-contact {
  display: flex; flex-wrap: wrap; gap: 8px 22px;
  margin-top: 12px;
}
.sig-contact a {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600;
  color: var(--chrome-ink2); text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--t), border-color var(--t);
}
.sig-contact a:hover { color: var(--amber); border-bottom-color: var(--amber); }
.sig-contact svg { width: 15px; height: 15px; flex: 0 0 15px; color: var(--amber); }
@media (max-width: 560px) { .sig-contact { gap: 6px 0; flex-direction: column; } }

/* ============================================================================
   22. Enquiry fallback
   Every call to action on this page is a mailto:. That does nothing at all on a
   machine with no mail client registered, which is common on Windows and is
   what makes a working button look broken. The link still fires first; if the
   page never loses focus, this panel offers the address, the pre-written
   message, a copy button and WhatsApp instead.
   ========================================================================== */

.enq-ov {
  position: fixed; inset: 0; z-index: 9800;
  background: rgba(10,15,8,.55);
  display: none; align-items: center; justify-content: center;
  padding: 20px;
}
.enq-ov.open { display: flex; }
.enq-box {
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--rail); border-radius: 4px;
  box-shadow: 0 30px 70px -20px rgba(0,0,0,.5);
  width: 560px; max-width: 100%; max-height: calc(100vh - 40px);
  display: flex; flex-direction: column;
}
.enq-hd {
  padding: 16px 20px; border-bottom: 2px solid var(--ink);
  font-size: 15px; font-weight: 800; letter-spacing: -.01em;
}
.enq-body { padding: 18px 20px; overflow: auto; }
.enq-body p { font-size: 14px; color: var(--ink2); line-height: 1.6; }
.enq-field {
  margin-top: 14px; border: 1px solid var(--line); border-radius: 3px;
  background: var(--panel);
}
.enq-field .k {
  display: block; padding: 7px 11px 0;
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink3);
}
.enq-field .v {
  display: block; padding: 3px 11px 9px;
  font-family: var(--mono); font-size: 13.5px; color: var(--ink);
  word-break: break-all;
}
.enq-field textarea {
  width: 100%; border: 0; background: transparent; resize: vertical;
  padding: 3px 11px 10px; min-height: 132px;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.55; color: var(--ink);
}
.enq-field textarea:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.enq-ft {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 14px 20px; border-top: 1px solid var(--line); background: var(--panel);
}
.enq-ft .btn { font-size: 12.5px; padding: 10px 15px; }
.enq-ft .sp { margin-left: auto; }
.enq-copied { font-size: 12px; font-weight: 700; color: var(--ok); align-self: center; }
@media (max-width: 560px) {
  .enq-ft { flex-direction: column; }
  .enq-ft .btn { width: 100%; }
  .enq-ft .sp { margin-left: 0; }
}

/* ============================================================================
   23. Rendering cost
   The page carries ~3,200 DOM nodes, most of them in faithful recreations of
   application screens. `content-visibility: auto` lets the browser skip layout,
   paint and style for a section until it is near the viewport, which cuts the
   first render substantially on a phone.

   contain-intrinsic-size gives each skipped section an assumed height so the
   scrollbar does not jump as sections are realised: without it this trades a
   rendering win for a CLS penalty, which would be a bad bargain for Core Web
   Vitals. The hero, the header and the first band are excluded: they are
   above the fold and skipping them would delay LCP rather than help it.
   ========================================================================== */

main > section.band:nth-of-type(n + 3) {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}
/* the 3D stage sizes itself from a canvas, so let it report its own height */
#batch3d { contain-intrinsic-size: auto 1100px; }
#screens { contain-intrinsic-size: auto 1400px; }
#faq     { contain-intrinsic-size: auto 1200px; }

/* Printing must not skip anything, and neither should a find-in-page on an
   engine that does not auto-reveal skipped content. */
@media print {
  main > section.band:nth-of-type(n + 3) { content-visibility: visible; }
}

/* ============================================================================
   24. Equation builder recreation
   Part of the database section. Colours are hard-coded like the rest of
   .appwin: it depicts the product, which has no dark mode, so a token here
   would flip with the site theme.
   ========================================================================== */

.eqx-scope {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: #eef1f5; border-bottom: 1px solid #ccd4dc;
  padding: 8px 12px;
}
.eqx-scope .l {
  font-family: var(--sans); font-size: 10px; font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase; color: #4b5763;
}
.eqx-expr { padding: 12px 13px 11px; border-bottom: 1px solid #e3e8ee; }
.eqx-expr .k {
  display: block; font-family: var(--mono);
  font-size: 9.5px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: #4b5763;
}
.eqx-expr b { display: block; font-size: 13.5px; font-weight: 800; color: #141a20; margin-top: 2px; }
.eqx-expr code {
  display: block; margin-top: 8px; padding: 10px 12px;
  background: #f6f8fa; border: 1.5px solid #9aa6b1; border-left: 3px solid #4a6320;
  border-radius: 3px;
  font-family: var(--mono); font-size: 13px; color: #2f4210;
  overflow-x: auto; white-space: nowrap;
}
.eqx-note { display: block; margin-top: 6px; font-size: 10.5px; color: #1f7a34; font-weight: 600; }

.eqx-pad {
  display: flex; flex-wrap: wrap; gap: 4px;
  padding: 10px 13px 12px; border-bottom: 1px solid #e3e8ee; background: #f6f8fa;
}
.eqx-pad span {
  min-width: 30px; padding: 6px 8px; text-align: center;
  background: #fff; border: 1px solid #ccd4dc; border-radius: 3px;
  font-family: var(--mono); font-size: 12px; font-weight: 700; color: #141a20;
}
.eqx-pad span.fn {
  font-family: var(--sans); font-size: 11px; color: #2f4210;
  background: #eaf0dd; border-color: #b9caa0;
}

@container (max-width: 420px) {
  .eqx-expr code { font-size: 11.5px; }
  .eqx-pad span { min-width: 26px; padding: 5px 6px; font-size: 11px; }
}

/* --- wide dropdown: every feature area without a scrolling list ----------- */
.dropdown-wide {
  display: grid;
  grid-template-columns: repeat(2, minmax(240px, 1fr));
  gap: 4px 10px;
  min-width: 560px;
}
.drop-col { min-width: 0; }
.drop-hd {
  display: block; padding: 6px 11px 5px;
  font-family: var(--mono);
  font-size: 9.5px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber);
}
/* it opens under the first nav item, so on a narrow desktop window it would
   otherwise run past the right edge: app.js clamps it, this keeps it sane */
@media (max-width: 1100px) {
  /* one column here, but NOT min-width:0, that removed the base minimum too
     and let the panel shrink to about 90px with the text wrapping to shreds.
     Ten entries in one column can also outrun a short window, so it scrolls. */
  .dropdown-wide {
    min-width: 320px;
    grid-template-columns: minmax(0, 1fr);
    max-height: calc(100vh - 130px);
    overflow-y: auto;
  }
  .dropdown-wide .drop-col + .drop-col { margin-top: 6px; }
}

/* --- category limits screen ---------------------------------------------- */
/* The Actual column is the whole point of the screen: it says whether the
   ration you have meets the band you just typed. Colour alone never carries
   that: the figure is also bracketed by its own Min and Max on the same row,
   and the note under the table states the rule in words. */
#screen-cat td.lim { color: #4b5763; }
#screen-cat td.ok  { color: #175c28; font-weight: 800; }
#screen-cat td.bad { color: #971f14; font-weight: 800; }
#screen-cat tr.hi  { background: #fbeceb; }
#screen-cat tr.hi td.nm { color: #971f14; }
#screen-cat td.ok .chip, #screen-cat td.bad .chip { margin-right: 6px; }

/* --- dropdown text must wrap ---------------------------------------------- */
/* `.nav a { white-space: nowrap }` keeps the top-level labels on one line, but
   .drop-link is also an <a> inside .nav and inherited it, so the descriptions
   could not wrap, ran past their grid column and printed over the next one.
   Re-enable wrapping inside the panel, and give the flex/grid children the
   min-width:0 they need to actually be allowed to shrink. */
.nav .drop-link,
.nav .drop-link .t,
.nav .drop-link .d { white-space: normal; overflow-wrap: anywhere; }
.dropdown-wide .drop-col { min-width: 0; }
.dropdown .drop-link { min-width: 0; }
.drop-link .d { max-width: 100%; }

/* ===========================================================================
   25. Category constraints dialog
   The application opens this over the formulation screen: a titled panel with
   a Min % and Max % box on every ingredient category. Recreated rather than
   screenshotted, so no plant or customer data can leak into the page.
   =========================================================================== */

.catdlg { border: 1px solid #b9c3cd; border-radius: 4px; overflow: hidden; background: #fff; }
.catdlg-hd {
  display: flex; align-items: center; gap: 10px;
  background: #556b2f; color: #fff;
  padding: 9px 12px; font-weight: 800; font-size: 12.5px;
}
.catdlg-hd .x { margin-left: auto; opacity: .85; font-weight: 700; }
.catdlg-note {
  padding: 8px 12px; background: #f6f8fa; border-bottom: 1px solid #ccd4dc;
  font-size: 10.5px; line-height: 1.5; color: #3d4753;
}
.catdlg-note b { color: #141a20; }

/* the rows scroll, as they do in the application: there are more categories
   than fit, and cutting the list would misrepresent it */
/* both axes: .catdlg has overflow:hidden for its rounded corners, so a table
   wider than a phone would be CLIPPED, not scrollable, without overflow-x here */
.catdlg-scroll { max-height: 292px; overflow: auto; }
.catdlg table { width: 100%; border-collapse: collapse; }
.catdlg thead th {
  position: sticky; top: 0; z-index: 1;
  background: #556b2f; color: #fff;
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 7px 9px; text-align: right; white-space: nowrap;
}
.catdlg thead th:first-child { text-align: left; }
.catdlg td {
  padding: 5px 9px; border-bottom: 1px solid #e6eaee;
  font-family: var(--mono); font-size: 11px; text-align: right; color: #26303a;
}
.catdlg td:first-child {
  font-family: var(--sans); font-weight: 600; color: #141a20; text-align: left;
}
.catdlg tbody tr:nth-child(even) { background: #fafbfc; }
/* #7c8894 measured 3.15-3.62:1 on these row fills - under AA. #5f6b76 clears
   4.5 on white, on the zebra fill AND on the highlighted row. */
.catdlg td.sel { color: #5f6b76; font-size: 10.5px; }

/* the boxes you type in. An empty one is a real, visible box holding a dash -
   that is what "blank means no limit" looks like on screen. */
.lim-in {
  display: inline-block; min-width: 62px; padding: 2px 6px;
  border: 1px solid #ccd4dc; background: #fbfcfd;
  font-family: var(--mono); font-size: 11px; text-align: right; color: #26303a;
}
/* the dash in an empty box was 1.98:1 - all but invisible, and it carries real
   meaning here (no limit set). Same accessible grey as Sel / Total. */
.lim-in.empty { color: #5f6b76; }
.lim-in.set { border-color: #8ea36a; background: #f4f8ec; font-weight: 700; color: #2f4014; }

.catdlg-foot {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; background: #f0f3f6; border-top: 1px solid #ccd4dc;
}
.catdlg-foot .sp { margin-left: auto; }
.catdlg-btn {
  padding: 4px 14px; border: 1px solid #b9c3cd; border-radius: 3px;
  background: #fff; font-size: 11px; font-weight: 700; color: #3d4753;
}
.catdlg-btn.clear { color: #971f14; border-color: #d9b3ae; }
.catdlg-btn.save  { background: #1f6b33; border-color: #1f6b33; color: #fff; }
.catdlg-btn.done  { background: #556b2f; border-color: #556b2f; color: #fff; }

@media (max-width: 560px) {
  .catdlg-scroll { max-height: 250px; }
  .lim-in { min-width: 50px; padding: 2px 4px; }
  .catdlg td, .catdlg thead th { padding-left: 6px; padding-right: 6px; }
}

/* ===========================================================================
   MOBILE LAST WORD
   This block has to sit at the END of the file. It was originally placed mid
   sheet and silently lost: later same-specificity rules (the datasheet pass
   restyles .eyebrow at line ~2127, for one) overrode it on source order, so
   the table sizes applied and the label sizes did not. Keep it last.
   =========================================================================== */
/* Squeezing the type to fit a narrow panel was the wrong trade: the tables
   already pan inside .tscroll, so shrinking bought nothing and cost legibility
   · 8.5px headers on a phone. Below, the type goes UP and the extra width is
   absorbed by the scroller, which is what it is there for. */
@media (max-width: 700px) {
  .appwin td, .catdlg td, .hs-tbl td, .rpt td { font-size: 13px; padding: 6px 9px; }
  .appwin th, .catdlg thead th, .hs-tbl th, .rpt th {
    font-size: 11px; padding: 7px 9px; letter-spacing: .03em;
  }
  .mock td { font-size: 12.5px; padding: 6px 8px; }
  .mock th { font-size: 11px; }
  .appwin .sec, .appwin-toolbar .chip2 { font-size: 11.5px; }
  .appwin-note, .stab-cap, .say-note, .al { font-size: 12.5px; line-height: 1.55; }
  .appwin-bar .t { font-size: 12px; }
  .appwin-cards .k, .diag-obj .k, .diag-meta .k { font-size: 10px; }
  .appwin-cards .v { font-size: 16px; }
  .pill, .chip { font-size: 11px; }
  .sc-card .k { font-size: 10.5px; }
  .sc-card .s, .co-item span { font-size: 12px; }
  .co-item b { font-size: 13px; }
  .hs-tot, .hs-cost div, .hs-status { font-size: 12px; }
  .lim-in, .ing-limbox { font-size: 12px; }
  /* the remaining small labels: eyebrows, chips, unit suffixes, rail items */
  .eyebrow { font-size: 11.5px; }
  /* the toolbar chips carry `font-size: inherit` at (0,2,1), which beats a bare
     .chip2 rule, so raise the bar they inherit from instead */
  .appwin-toolbar, .chip2 { font-size: 11.5px; }
  .appwin i, .homewin i, .mock i, .hs-cost i { font-size: 11px; }
  .hs-item, .hs-grp, .hs-rail .k { font-size: 11px; }
  .sc-ctl .l, .sc-ctl .f, .eqx-scope .l { font-size: 11.5px; }
  .mock .k, .appwin .k, .homewin .k, .diag-obj .k, .diag-meta .k { font-size: 11px; }
  /* every link and button gets a real touch target */
  a, button, [role="tab"] { min-height: 24px; }
  .card-lnk, .lnk, .foot-links a { display: inline-flex; align-items: center; min-height: 32px; }

  /* A table that pans is not obvious on a phone. When one actually overflows,
     its right edge fades: the standard cue that there is more that way. The
     fade is dropped once you reach the end, so it never lies. */
  .tscroll[data-pan="1"], .catdlg-scroll[data-pan="1"] {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  }
}

/* ══ multi-page additions ══════════════════════════════════════════════════
   The site became a page per topic; these are the three components that only
   exist because of that: the home page's card grid, the album page's message
   preview, and the strip of sample album pages. */

/* ---- home: one card per page ------------------------------------------- */
.nav-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 26px 24px 22px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  color: inherit; text-decoration: none;
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.nav-card:hover, .nav-card:focus-visible {
  transform: translateY(-3px);
  border-color: var(--accent);
  box-shadow: 0 10px 30px rgba(12, 18, 25, .10);
}
.nav-card h3 { font: 600 19px/1.25 var(--sans); color: var(--ink); margin: 0; }
.nav-card p  { font: 400 15px/1.55 var(--sans); color: var(--ink2); margin: 0; flex: 1; }
.nav-card .card-ic {
  width: 38px; height: 38px; display: grid; place-items: center;
  border-radius: 9px; background: var(--accent-soft); color: var(--accent);
}
.nav-card .card-ic svg { width: 20px; height: 20px; }
.nav-card-go {
  display: inline-flex; align-items: center; gap: 7px;
  font: 600 14px/1 var(--sans); color: var(--action); margin-top: 4px;
}
.nav-card-go .ic { width: 15px; height: 15px; transition: transform var(--t); }
.nav-card:hover .nav-card-go .ic { transform: translateX(3px); }
/* the album card is the one action this page most wants pressed */
.nav-card-accent { border-color: var(--accent); background: var(--accent-soft); }

/* ---- album: the message, shown before it is sent ------------------------ */
.msg-preview {
  margin-top: 18px; border: 1px solid var(--chrome-line); border-radius: 10px;
  background: rgba(0, 0, 0, .22); overflow: hidden;
}
.msg-hd {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px; border-bottom: 1px solid var(--chrome-line);
  font: 600 12.5px/1 var(--sans); color: var(--chrome-ink2);
  text-transform: uppercase; letter-spacing: .06em;
}
.msg-preview pre {
  margin: 0; padding: 14px 14px 16px;
  font: 400 13.5px/1.6 var(--mono); color: var(--chrome-ink);
  white-space: pre-wrap; word-break: break-word;
}
.btn-sm { padding: 5px 11px; font-size: 12.5px; }

/* ---- album: three sample pages ----------------------------------------- */
.album-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.album-strip img {
  width: 100%; height: auto; display: block; border-radius: 8px;
  border: 1px solid var(--chrome-line);
}
/* On a phone, three across is ~110px each: the card titles stop being
   readable and the point of showing them is lost. Below 560px the strip
   becomes a swipe instead, at a width you can actually read, following the
   same sideways-scroll idiom the app tables use elsewhere on the site. */
@media (max-width: 560px) {
  .album-strip {
    display: flex; gap: 10px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    /* bleed to the screen edge so a half-visible next card says 'swipe me' */
    margin-inline: -22px;                    /* .wrap padding, so it bleeds to the edge */
    padding-inline: 22px;
    scrollbar-width: none;
  }
  .album-strip::-webkit-scrollbar { display: none; }
  .album-strip img { flex: 0 0 76%; scroll-snap-align: center; }
  .msg-hd { flex-wrap: wrap; }
}
