/* Inplant AI — marketing site.
 *
 * Fonts are self-hosted in fonts/. The site's central claim is that nothing
 * leaves the building, and a page making that argument while calling
 * fonts.googleapis.com is an argument against itself. url() below resolves
 * relative to this stylesheet, so blog/ pages get the same faces.
 *
 * Light only, deliberately. The palette is paper and ink with one signal
 * colour, and a dark inversion would need a second set of decisions about
 * what "signal" means against black. The dark band does that job instead.
 */

@import url("fonts.css");

:root {
  color-scheme: light only;

  --paper: #fafaf8;
  --card: #ffffff;
  --ink: #0b0c0b;
  --steel: #70736e;
  /* The same grey inverted is not the same grey: #70736e measures 4.00 on the
   * dark band and 3.57 on the panel, both under AA. This one clears both. */
  --steel-dark: #80847e;
  --rule: #e3e3de;
  --dark: #0d0f0e;
  --dark-2: #191c1a;
  --sig: #f4520f;
  /* The same hue, dark enough to be read. #f4520f measures 3.31 against the
   * page and AA wants 4.5, so orange that is *text* on a light ground uses
   * this instead. Fills, marks and large numerals keep the brand orange. */
  --sig-text: #cf4309;
  --green: #1f7a47;
  /* Neither of the greys tried here worked, and the reason was structural
   * rather than a matter of shade: a fill one or two steps off the page is the
   * hardest thing on a screen to read as intentional. The panel commits to ink
   * instead. */
  --panel: #101211;
  --rule-panel: rgba(255, 255, 255, 0.13);

  /* One family, weight for contrast. Geist was drawn for technical product
   * interfaces, which is what this is — and a display face borrowed from a
   * different foundry than the body face is a seam a reader can feel. */
  --disp: "Instrument Sans", system-ui, sans-serif;
  --font: "Instrument Sans", system-ui, sans-serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Type scale — a 1.25 ratio, fluid between a phone and a desk. Sizes that
   * are not on this list are bugs, not decisions. */
  --t-mono: 10.5px;
  --t-xs: 13px;
  --t-sm: 14px;
  --t-md: 15.5px;
  --t-base: 17px;
  --t-lg: clamp(17px, 1.1vw, 19px);
  --t-xl: clamp(21px, 1.6vw, 24px);
  --t-2xl: clamp(26px, 3vw, 40px);
  --t-3xl: clamp(30px, 4.2vw, 52px);
  --t-4xl: clamp(34px, 4.8vw, 60px);
  --t-5xl: clamp(40px, 5.6vw, 76px);

  /* Spacing scale. Same rule. */
  --s-1: 8px;
  --s-2: 14px;
  --s-3: 20px;
  --s-4: 32px;
  --s-5: 52px;
  --s-6: clamp(30px, 5vw, 72px);
  --s-7: clamp(58px, 8vw, 116px);

  --gut: clamp(20px, 4vw, 72px);
  /* 1240 was a reading measure applied to a whole page. Body copy still gets
   * one via .narrow; the page itself should use the display it is on. */
  --wide: 1560px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--disp);
  font-weight: 700;
  letter-spacing: -0.032em;
  line-height: 1.02;
  margin: 0;
}
p { margin: 0; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--sig); outline-offset: 3px; }

.wrap { max-width: var(--wide); margin: 0 auto; padding: 0 var(--gut); }
.wrap.narrow { max-width: 46rem; }

.eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--steel);
}
.rule { height: 1px; background: var(--rule); }
.dim { color: var(--steel); }

/* --- nav ------------------------------------------------------------------ */

.nav { border-bottom: 1px solid var(--rule); }
.nav-in {
  max-width: var(--wide); margin: 0 auto; padding: 20px var(--gut);
  display: flex; align-items: center; gap: 34px;
}
.brand {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--disp); font-weight: 700; font-size: 20px;
  letter-spacing: -0.038em; text-decoration: none;
}
.brand-mark {
  width: 11px; height: 11px; background: var(--sig); display: block;
  text-indent: -9999px; overflow: hidden;
}
.nav-link {
  font-size: 14.5px; font-weight: 500; color: var(--steel);
  text-decoration: none; transition: color 0.12s;
}
.nav-link:hover { color: var(--ink); }
.spacer { flex: 1; }

@media (max-width: 940px) {
.nav-link { display: none; }
}

/* --- buttons -------------------------------------------------------------- */

.btn {
  display: inline-block; font-family: var(--font); font-weight: 600;
  font-size: 14px; padding: 10px 18px; border-radius: 0;
  text-decoration: none; border: 1px solid var(--ink); white-space: nowrap;
  background: var(--ink); color: #fff;
  transition: background 0.14s, color 0.14s, border-color 0.14s;
}
.btn:hover { background: var(--sig); border-color: var(--sig); }
.btn-primary { background: var(--ink); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { background: var(--ink); color: #fff; border-color: var(--ink); }
.btn-inv { background: #fff; border-color: #fff; color: var(--dark); }
.btn-inv:hover { background: var(--sig); border-color: var(--sig); color: #fff; }
.btn-inv-ghost { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.35); }
.btn-inv-ghost:hover { background: #fff; color: var(--dark); border-color: #fff; }

.hero-actions, /* The unit has a name and a number, and the hero is where a buyer decides
 * whether to keep reading. Under the subhead rather than beside the buttons:
 * it is a fact about the product, not an action. */
.pricetag {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  margin-top: var(--s-3);
}
.pt-name {
  font-family: var(--disp);
  font-weight: 600;
  font-size: var(--t-base);
  letter-spacing: -0.02em;
  color: var(--ink);
}
.pt-amt {
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--steel);
}

.actions {
  display: flex; gap: 10px; margin-top: 36px; flex-wrap: wrap; align-items: center;
}
.hero-note { font-family: var(--mono); font-size: 11.5px; color: var(--steel); }

/* --- dark band ------------------------------------------------------------ */

/* Bands carry the page's own vertical rhythm, the same clamp `section` uses.
 *
 * They had no vertical padding at all and leaned on whatever margin their
 * contents happened to have. That held until the essay under the price was
 * removed and the investment band was added with neither, at which point the
 * chart's bottom border sat exactly on the band's edge. The hero is excluded:
 * .hero-full sets its own. */
.band { background: var(--dark); color: #fff; }
.band:not(.paper) { padding: var(--s-7) 0; }
.band .eyebrow { color: var(--steel-dark); }
.band h1 {
  font-size: clamp(40px, 5.8vw, 76px); font-weight: 700; color: #fff;
  letter-spacing: -0.034em;
}
.band h2 { font-size: clamp(38px, 5.6vw, 72px); font-weight: 700; color: #fff; }
.band .sub { margin-top: 22px; color: #9da29c; font-size: 19px; max-width: 22em; }

.showcase {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(30px, 6vw, 80px); align-items: center;
}
@media (max-width: 940px) {
.showcase { grid-template-columns: 1fr; gap: 20px; }
}

/* The appliance. Built from six divs rather than a photograph because there is
 * no photograph to take yet, and a render that admits it is a render reads
 * more honestly than a stock image of someone else's server. */
.stage {
  display: flex; align-items: center; justify-content: center;
  min-height: min(66vh, 600px); perspective: 1600px; position: relative;
}
.tower {
  position: relative; width: 182px; height: 406px;
  transform-style: preserve-3d; transform: rotateX(4deg) rotateY(-22deg);
  animation: turn 1.25s cubic-bezier(0.2, 0.75, 0.28, 1) both;
}
@keyframes turn {
  from { transform: rotateX(4deg) rotateY(-38deg); }
  to { transform: rotateX(4deg) rotateY(-22deg); }
}
.face { position: absolute; border-radius: 0; }
.f-front {
  width: 182px; height: 406px;
  background: linear-gradient(165deg, #3a3e3b 0%, #242825 44%, #151816 100%);
  transform: translateZ(74px);
  box-shadow: inset 0 1.5px 0 rgba(255, 255, 255, 0.16);
}
.f-side {
  width: 148px; height: 406px;
  background: linear-gradient(165deg, #1d211e, #0e1110);
  transform: rotateY(90deg) translateZ(91px); left: 17px;
}
.f-top {
  width: 182px; height: 148px;
  background: linear-gradient(148deg, #474c48, #2b302c);
  transform: rotateX(90deg) translateZ(74px); top: -74px;
}
.perf {
  position: absolute; top: 34px; left: 32px; right: 32px; height: 228px;
  transform: translateZ(75px);
  background: radial-gradient(circle, rgba(255, 255, 255, 0.16) 1.3px, transparent 1.5px);
  background-size: 11px 11px;
}
.dotmark {
  position: absolute; top: 34px; left: 32px; width: 33px; height: 22px;
  transform: translateZ(76px);
  background: radial-gradient(circle, var(--sig) 1.7px, transparent 1.9px);
  background-size: 11px 11px;
}
.base {
  position: absolute; bottom: -9px; left: 9px; width: 164px; height: 10px;
  background: linear-gradient(180deg, #5a605b, #2e332f);
  transform: translateZ(74px); border-radius: 0 0 4px 4px;
}
.glow {
  position: absolute; bottom: 8%; left: 50%; transform: translateX(-50%);
  width: 420px; height: 180px;
  background: radial-gradient(ellipse at 50% 100%, rgba(244, 82, 15, 0.13), transparent 70%);
  pointer-events: none;
}

/* --- sections ------------------------------------------------------------- */

section { padding: clamp(58px, 8vw, 116px) 0; }

.sec-head { max-width: 42rem; margin-bottom: 52px; }
.sec-head h2 { font-size: clamp(30px, 4.2vw, 52px); margin-top: 16px; font-weight: 700; }
.sec-head p { margin-top: 20px; color: var(--steel); font-size: 18px; }

  font-size: clamp(34px, 4.8vw, 60px); font-weight: 700;
  letter-spacing: -0.042em; line-height: 1;
}
.explain h2 span { display: block; color: var(--steel); }
.explain .lede { margin-top: 26px; font-size: 19px; color: var(--steel); line-height: 1.6; }
.explain .lede b { color: var(--ink); font-weight: 600; }

.hero { padding: clamp(52px, 8vw, 116px) 0; }
.lede { font-size: 18px; color: var(--steel); max-width: 34em; line-height: 1.6; }
.fine { margin-top: 20px; font-family: var(--mono); font-size: 11.5px; color: var(--steel); }
.fine sup { color: var(--sig-text); }

.grid-2 { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: clamp(30px, 5vw, 64px); align-items: center; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 940px) {
.grid-2 { grid-template-columns: 1fr; }
}
@media (max-width: 1020px) {
.grid-3 { grid-template-columns: 1fr; }
}

/* --- stats strip ---------------------------------------------------------- */

.stats, .specbar-in {
  display: grid; grid-template-columns: repeat(5, 1fr);
  padding: clamp(30px, 4vw, 48px) 0;
  max-width: var(--wide); margin: 0 auto;
}
.stats > div, .spec { border-left: 1px solid var(--rule); padding: 4px 0 4px 18px; }
.stats > div:first-child, .spec:first-child { border-left: 0; padding-left: 0; }
.stats b, .spec .n {
  display: block; font-family: var(--disp); font-weight: 700;
  font-size: clamp(26px, 3.1vw, 40px); letter-spacing: -0.034em; line-height: 1;
}
.spec .n small { font-size: 0.5em; font-weight: 600; letter-spacing: 0; }
.stats span, .spec .l {
  display: block; margin-top: 10px; font-size: 13.5px;
  color: var(--steel); line-height: 1.4;
}
.specbar { border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.specbar-in { padding-left: var(--gut); padding-right: var(--gut); }
@media (max-width: 900px) {
.stats, .specbar-in { grid-template-columns: 1fr 1fr; gap: 26px 0; }
  .stats > div:nth-child(odd), .spec:nth-child(odd) { border-left: 0; padding-left: 0; }
}

/* --- the unit ------------------------------------------------------------- */

.unit-sec {
  display: grid; grid-template-columns: 0.92fr 1.08fr;
  gap: clamp(30px, 5vw, 72px); align-items: center;
}
@media (max-width: 940px) {
.unit-sec { grid-template-columns: 1fr; }
}

.elev { background: var(--card); border: 1px solid var(--rule); border-radius: 0; padding: 24px; }
.elev svg { width: 100%; height: auto; display: block; }
.elev svg[hidden] { display: none; }

.toggle {
  display: inline-flex; border: 1px solid var(--rule);
  border-radius: 0; overflow: hidden; margin-bottom: 20px;
}
.toggle button {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; padding: 9px 18px; border: 0;
  background: transparent; color: var(--steel); cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.toggle button + button { border-left: 1px solid var(--rule); }
.toggle button[aria-selected="true"] { background: var(--ink); color: #fff; }
.toggle button[aria-selected="false"]:hover { background: rgba(11, 12, 11, 0.05); color: var(--ink); }

.speclist { list-style: none; padding: 0; margin: 30px 0 0; border-top: 1px solid var(--rule); }
.speclist li {
  display: flex; justify-content: space-between; gap: 20px;
  padding: 14px 0; border-bottom: 1px solid var(--rule);
  font-size: 15px; font-weight: 500;
}
.speclist li span:last-child {
  font-family: var(--mono); font-size: 13px; color: var(--steel);
  text-align: right; font-weight: 400;
}

/* --- trio / cards --------------------------------------------------------- */

.trio {
  display: grid; grid-template-columns: repeat(3, 1fr);
  border: 1px solid var(--rule); border-radius: 0;
  background: var(--card); overflow: hidden;
}
.trio.duo { grid-template-columns: repeat(2, 1fr); }
/* Four across for the suite. Collapses to two before it collapses to one,
 * because four modules stacked is a very long column on a tablet. */
.trio.quad { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1080px) {
.trio.quad { grid-template-columns: repeat(2, 1fr); }
}
/* The rule that collapses .trio to one column names .trio and .trio.duo, so
 * a quad kept two columns all the way down to a phone. */
@media (max-width: 700px) { .trio.quad { grid-template-columns: 1fr; } }
/* The kicker sits above the name, so the four read as a set rather than as
 * four unrelated headings. Mono and tracked, like every other label here. */
/* The icon tells the four apart before the words do, which is what lets the
 * words be this short. Orange, like the only other mark on the page. */
.mod-ic {
  width: 24px; height: 24px;
  /* stroke, not color: this is a graphical object, where the bar is 3.0 and
   * the brand orange clears it. Saying `color` made it look like text to
   * anything reading the stylesheet, including our own contrast test. */
  stroke: var(--sig);
  display: block;
}

/* Under the description rather than above the name: it is a footnote about
 * when the thing runs, not a heading. */
.mod-k {
  margin-top: var(--s-2);
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
}
.trio.quad h3 { margin-top: var(--s-2); font-size: var(--t-lg); }
.trio.quad p { font-size: var(--t-sm); }

.suite-foot {
  margin-top: var(--s-3);
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink);
}
.trio > div { padding: clamp(24px, 3vw, 38px); border-right: 1px solid var(--rule); }
.trio > div:last-child { border-right: 0; }
.trio h3 { font-size: 21px; font-weight: 700; letter-spacing: -0.03em; margin: 12px 0; }
.trio p { color: var(--steel); font-size: 15.5px; line-height: 1.6; }
@media (max-width: 900px) {
.trio, .trio.duo { grid-template-columns: 1fr; }
  .trio > div { border-right: 0; border-bottom: 1px solid var(--rule); }
  .trio > div:last-child { border-bottom: 0; }
}

.card { background: var(--card); border: 1px solid var(--rule); border-radius: 0; padding: clamp(24px, 3vw, 38px); }
.card h3 { font-size: 21px; font-weight: 700; letter-spacing: -0.03em; margin: 12px 0; }
.card p { color: var(--steel); font-size: 15.5px; line-height: 1.6; }

/* --- answer cards (homepage) ---------------------------------------------- *
 * .qa, not .answer — blog posts already use .answer for their GEO answer
 * blocks and the two are different objects. */

.qa {
  background: var(--card); border: 1px solid var(--rule); border-radius: 0;
  box-shadow: 0 26px 50px -38px rgba(11, 12, 11, 0.5); overflow: hidden;
}
.qa .q {
  padding: 15px 20px; border-bottom: 1px solid var(--rule);
  font-size: 13.5px; color: var(--steel); font-weight: 500;
}
.qa .q b { color: var(--ink); font-weight: 600; }
.qa .a { padding: 20px; font-size: 16.5px; line-height: 1.55; }
.qa .a strong {
  font-family: var(--mono); font-weight: 500;
  border-bottom: 2px solid var(--sig); padding-bottom: 1px;
}
.thumb {
  height: 132px; background: var(--dark-2); border-bottom: 1px solid var(--rule);
  display: flex; align-items: flex-end; padding: 12px 16px;
  font-family: var(--mono); font-size: 10.5px; color: #7e837d;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.09) 1px, transparent 1.2px);
  background-size: 12px 12px;
}
.tb { margin: 0; border-top: 1px solid var(--rule); display: grid; grid-template-columns: 2fr 1fr 1fr; }
.tb div { padding: 11px 16px; border-right: 1px solid var(--rule); }
.tb div:first-child { box-shadow: inset 3px 0 0 var(--sig); }
.tb div:last-child { border-right: 0; }
.tb dt {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--steel); margin: 0 0 4px;
}
.tb dd {
  font-family: var(--mono); font-size: 12px; margin: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tb .ok { color: var(--green); }
.tb.none div:first-child { box-shadow: inset 3px 0 0 var(--steel); }
@media (max-width: 430px) {
.tb { grid-template-columns: 1fr 1fr; }
  .tb div:first-child { grid-column: 1 / -1; border-right: 0; border-bottom: 1px solid var(--rule); }
}

/* --- comparison table ----------------------------------------------------- */

.cmp {
  width: 100%; border-collapse: collapse; border: 1px solid var(--rule);
  border-radius: 0; overflow: hidden; background: var(--card); font-size: 15.5px;
}
.cmp th, .cmp td { text-align: left; padding: 15px 18px; border-bottom: 1px solid var(--rule); font-weight: 400; }
.cmp thead th {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--steel); background: var(--paper);
}
.cmp tbody th { font-weight: 600; width: 34%; }
.cmp td { color: var(--steel); }
.cmp .us { color: var(--ink); box-shadow: inset 3px 0 0 var(--sig); }
.cmp thead th.us { color: var(--ink); font-weight: 500; }
.cmp tbody tr:last-child th, .cmp tbody tr:last-child td { border-bottom: 0; }
@media (max-width: 680px) {
.cmp { font-size: 14px; }
  .cmp th, .cmp td { padding: 12px; }
  .cmp tbody th { width: 38%; }
}
.table-scroll { overflow-x: auto; }
.table-scroll table { width: 100%; border-collapse: collapse; font-size: 15px; }
.table-scroll th, .table-scroll td {
  text-align: left; padding: 12px 16px; border-bottom: 1px solid var(--rule);
}
.table-scroll thead th {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--steel);
}

/* --- pricing -------------------------------------------------------------- */

.price-head h2 { font-size: clamp(30px, 4.2vw, 52px); font-weight: 700; }
.plans {
  display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--rule);
  border-top: 0; border-radius: 0; overflow: hidden; background: var(--card);
}
.plan { padding: clamp(28px, 3.6vw, 44px); border-right: 1px solid var(--rule); }
.plan:last-child { border-right: 0; }
.plan-amt sub {
  font-family: var(--font); font-size: 14.5px; font-weight: 500;
  color: var(--steel); vertical-align: baseline; letter-spacing: 0;
}
.plan p { color: var(--steel); font-size: 15.5px; line-height: 1.65; }
@media (max-width: 860px) {
.plans { grid-template-columns: 1fr; }
  .plan { border-right: 0; border-bottom: 1px solid var(--rule); }
  .plan:last-child { border-bottom: 0; }
}

/* --- pipeline / negative list --------------------------------------------- */

.pipe { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; border: 1px solid var(--rule); border-radius: 0; overflow: hidden; background: var(--card); }
.pipe-step { padding: clamp(20px, 2.6vw, 30px); border-right: 1px solid var(--rule); }
.pipe-step:last-child { border-right: 0; }
.pipe-step h3 { font-size: 17px; font-weight: 700; margin: 10px 0 10px; letter-spacing: -0.02em; }
.pipe-step p { color: var(--steel); font-size: 14.5px; line-height: 1.55; }
@media (max-width: 900px) {
.pipe { grid-template-columns: 1fr; }
  .pipe-step { border-right: 0; border-bottom: 1px solid var(--rule); }
  .pipe-step:last-child { border-bottom: 0; }
}

.nots { list-style: none; padding: 0; margin: 0; }
.nots li { padding: 16px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.14); font-size: 16.5px; }
.nots li:last-child { border-bottom: 0; }
.nots b { font-weight: 600; }

/* --- blog ----------------------------------------------------------------- */

.post { padding: clamp(40px, 6vw, 72px) 0; }
.post h1 { font-size: clamp(30px, 4.4vw, 52px); font-weight: 700; margin-bottom: 20px; }
.post h2 { font-size: clamp(24px, 2.8vw, 34px); font-weight: 700; margin: 52px 0 18px; }
.post h3 { font-size: 20px; font-weight: 700; margin: 34px 0 12px; }
.post p { margin: 0 0 20px; font-size: 17.5px; line-height: 1.68; }
.post ul, .post ol { margin: 0 0 22px; padding-left: 22px; }
.post li { margin-bottom: 10px; font-size: 17.5px; line-height: 1.6; }
.post a { color: var(--sig-text); text-decoration: underline; text-underline-offset: 2px; }
.post code {
  font-family: var(--mono); font-size: 0.88em;
  background: #f0f0ec; padding: 2px 5px; border-radius: 3px;
}
.post-meta { font-family: var(--mono); font-size: 11.5px; color: var(--steel); margin-bottom: 28px; }

.answer {
  border-left: 3px solid var(--sig); background: #fff4ee;
  padding: 18px 22px; border-radius: 0; margin: 26px 0 34px;
}
.answer p { margin: 0; color: var(--ink); font-size: 17.5px; }

.callout {
  border: 1px solid var(--rule); border-radius: 0;
  padding: 18px 22px; margin: 28px 0; background: var(--card);
}
.callout p:last-child { margin-bottom: 0; }

.faq { border-top: 1px solid var(--rule); padding-top: 8px; margin-top: 40px; }
.faq-q { font-family: var(--disp); font-weight: 700; font-size: 19px; margin: 28px 0 10px; letter-spacing: -0.02em; }
.num { font-family: var(--mono); font-size: 0.94em; }

.postlist { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--rule); }
.postlist li { border-bottom: 1px solid var(--rule); }
.postlist a { display: block; padding: 28px 0; text-decoration: none; }
.postlist a:hover .pl-title { color: var(--sig-text); }
.pl-kicker { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--steel); }
.pl-title { font-family: var(--disp); font-weight: 700; font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -0.026em; margin: 10px 0 10px; transition: color 0.12s; }
.pl-sum { color: var(--steel); font-size: 16px; max-width: 46rem; }

/* --- mock (legacy hero answer) -------------------------------------------- */

.mock { background: var(--card); border: 1px solid var(--rule); border-radius: 0; overflow: hidden; box-shadow: 0 26px 50px -38px rgba(11, 12, 11, 0.5); }
.mock-bar { padding: 13px 18px; border-bottom: 1px solid var(--rule); font-family: var(--mono); font-size: 11px; color: var(--steel); display: flex; align-items: center; gap: 8px; }
.mock-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--sig); display: block; }
.mock-body { padding: 20px; }
.mock-q { font-size: 14px; color: var(--steel); margin-bottom: 14px; }
.mock-a { font-size: 17px; line-height: 1.55; }
.mock-cite { display: inline-block; margin-top: 12px; font-family: var(--mono); font-size: 12px; color: var(--sig-text); }
.mock-meta { font-family: var(--mono); font-size: 11px; color: var(--steel); }

/* --- footer --------------------------------------------------------------- */

footer { border-top: 1px solid var(--rule); padding: 40px 0 64px; font-size: 13px; color: var(--steel); }
.foot-in { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.foot-note { font-family: var(--mono); font-size: 11px; line-height: 1.8; max-width: 64rem; }
.foot-note sup { color: var(--sig-text); }

/* --- motion --------------------------------------------------------------- */

.r1, .r2 { opacity: 0; transform: translateY(8px); animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
.r1 { animation-delay: 0.28s; }
.r2 { animation-delay: 0.86s; }
@keyframes rise { to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
  .tower { animation: none; }
  .r1, .r2 { animation: none; opacity: 1; transform: none; }
}

/* --- homepage without a nav ----------------------------------------------- *
 * The operator this page is for arrives from a link or a QR code on the
 * machine, not from a menu. The brand sits in the hero and the footer carries
 * the two links anyone actually follows. */

.brand-hero { font-size: 22px; color: #fff; }
.brand-hero .brand-mark { width: 12px; height: 12px; }

.specbar-in.three { grid-template-columns: repeat(3, 1fr); }
.specbar-in.four { grid-template-columns: repeat(4, 1fr); }
.specbar-in.three .spec .n,
.specbar-in.four .spec .n { font-size: clamp(24px, 2.6vw, 34px); }
.specbar-in.three .spec .n small,
.specbar-in.four .spec .n small { font-size: 0.62em; font-weight: 500; }
.specbar-in.three .spec .l,
.specbar-in.four .spec .l { max-width: 26em; }
@media (max-width: 900px) {
.specbar-in.three, .specbar-in.four { grid-template-columns: 1fr 1fr; gap: 26px 0; }
  .specbar-in.three .spec, .specbar-in.four .spec { border-left: 0; padding-left: 0; }
}

/* --- the product ---------------------------------------------------------- *
 * Photograph on a knocked-out background, so it sits directly on the band with
 * the orange bloom behind it rather than inside a white plate. The CSS render
 * it replaced is gone; keeping both would have meant two answers to "what does
 * it look like". */

.appliance {
  position: relative;
  z-index: 1;
  width: auto;
  max-width: 100%;
  height: clamp(300px, 46vw, 520px);
  object-fit: contain;
  filter: drop-shadow(0 40px 60px rgba(0, 0, 0, 0.55));
}
@media (max-width: 940px) {
.stage { min-height: 0; padding: 8px 0 24px; }
  .appliance { height: clamp(240px, 54vw, 360px); }
}

/* --- hero on paper -------------------------------------------------------- *
 * The product shot is lit on white, so the page meets it rather than fighting
 * it: pure white ground, the photograph's own shadow doing the grounding, and
 * no knockout edge to get wrong. Ink text, dark buttons, orange stays the one
 * signal colour. */

.band.paper {
  background: #ffffff;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.band.paper h1 { color: var(--ink); }
.band.paper .sub { color: var(--steel); }
.band.paper .eyebrow { color: var(--steel); }
.band.paper .appliance {
  height: clamp(300px, 46vw, 540px);
  filter: none;                    /* the shadow is in the pixels already */
  mix-blend-mode: multiply;        /* melts the last of the studio white */
}
@media (max-width: 940px) {
.band.paper .appliance { height: clamp(200px, 46vw, 320px); }
}

/* --- full-height hero ----------------------------------------------------- *
 * The first screen is the product and one sentence. Sizing it to the viewport
 * rather than to its own padding means the fold lands where it was designed
 * to, on any display. svh, not vh: mobile browsers shrink the viewport as the
 * URL bar retracts, and vh would leave the hero taller than the screen. */

.hero-full {
  padding: 0;
  min-height: calc(100svh - 84px);
  display: flex;
  align-items: center;
}
.hero-full > .wrap { width: 100%; }

/* Image hard left, and a wider trough between it and the words. The stage no
 * longer centres its contents — centring inside a column just reintroduced the
 * gap on the wrong side. */
.band.paper .showcase {
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(32px, 8vw, 132px);
  align-items: center;
}
.band.paper .stage {
  justify-content: flex-start;
  min-height: 0;
  margin-left: 0;   /* aligns with the wordmark now that the page is wider */
}
.band.paper .appliance { height: min(62svh, 560px); }

@media (max-width: 940px) {
.hero-full { min-height: 0; padding: 24px 0 48px; }
  /* The product sits at 72% of the image width — the shadow trails left — so
   * centring the image leaves the machine off to the right. Shift by the
   * measured offset to centre the thing rather than the file. */
  .band.paper .stage { justify-content: center; margin-left: 0; }
  .band.paper .appliance { transform: translateX(-11%); }
  .band.paper .appliance { height: clamp(200px, 46vw, 320px); }
}

/* The hero runs wider still — it is a product shot and six words, and capping
 * it at the body measure left the machine stranded in the middle of the page. */
.hero-full > .wrap { max-width: min(1860px, 100%); }

/* --- copy beside the numbers ---------------------------------------------- *
 * The explain block was 46rem of text with an empty half-page beside it. The
 * stats used to sit under it as a full-width rule of four, which read as a
 * separate exhibit; alongside, they read as evidence for the paragraph. */

.explain-grid .explain { padding: 0; max-width: 40rem; }

/* --- classes that replaced inline styles ---------------------------------- */

.flush { padding-left: 0 !important; padding-right: 0 !important; }
.mt-3 { margin-top: var(--s-3); }
.mt-4 { margin-top: var(--s-4); }
.h2 { font-size: var(--t-3xl); font-weight: 700; }
.lead-sm { color: var(--steel); font-size: var(--t-lg); }
.note { color: var(--steel); font-size: var(--t-md); max-width: 42rem; }
.col-narrow { max-width: 580px; }
/* Specificity, not order: `.sec-head p` also sets a colour, so `.on-dark`
 * alone loses to it and the dark band kept the light-ground grey. */
.on-dark, .band .sec-head p, .band .on-dark { color: var(--steel-dark); }
.lnk-sig { color: var(--sig-text); }
.lnk-quiet { color: var(--steel); }

/* --- the unit, photographed ----------------------------------------------- *
 * Replaces a pair of hand-drawn SVG elevations. Those described a machine that
 * was not the one in the hero, which is a worse problem than a plain photo
 * having no dimension lines on it — the datasheet carries the measurements. */

.unit-shot {
  margin: 0;
  background: var(--panel);
  padding: clamp(24px, 4vw, 56px);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.unit-shot img {
  width: 100%;
  max-width: 420px;
  height: auto;
  display: block;
  mix-blend-mode: multiply;
}

/* --- motion ---------------------------------------------------------------- *
 * Only ever applied when the script confirms it will run. .will-reveal is set
 * by JS, so no-JS and reduced-motion readers get the finished page directly
 * rather than a stack of blocks stuck at opacity 0. */

.will-reveal .reveal {
  opacity: 0;
  transform: translateY(18px);
}
.will-reveal .reveal.shown {
  opacity: 1;
  transform: none;
  transition: opacity 0.62s cubic-bezier(0.22, 0.7, 0.25, 1),
              transform 0.62s cubic-bezier(0.22, 0.7, 0.25, 1);
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

/* The hero is above the fold, so it animates on load rather than on scroll. */
.band.paper .appliance {
  animation: settle 0.9s cubic-bezier(0.2, 0.75, 0.28, 1) both;
}
.band.paper .eyebrow,
.band.paper h1,
.band.paper .sub,
.band.paper .actions {
  animation: rise-in 0.7s cubic-bezier(0.22, 0.7, 0.25, 1) backwards;
}
.band.paper .eyebrow { animation-delay: 0.10s; }
.band.paper h1 { animation-delay: 0.17s; }
.band.paper .sub { animation-delay: 0.25s; }
.band.paper .actions { animation-delay: 0.33s; }
@keyframes settle {
  from { opacity: 0; transform: translateY(20px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

/* --- the accent, doing work ------------------------------------------------ *
 * It was an 11px square and an asterisk. A signal colour that never signals is
 * decoration. Now it marks the thing under the cursor, and the one number on
 * the page that is a promise rather than a measurement. */

.nav-link { position: relative; }
.nav-link::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -5px;
  height: 2px; background: var(--sig);
  transition: right 0.26s cubic-bezier(0.22, 0.7, 0.25, 1);
}
.nav-link:hover::after { right: 0; }

.qa { transition: transform 0.24s cubic-bezier(0.22, 0.7, 0.25, 1), box-shadow 0.24s, border-color 0.24s; }
.qa:hover { transform: translateY(-3px); border-color: #cfcdc5; box-shadow: 0 30px 55px -40px rgba(11, 12, 11, 0.6); }

.trio > div, .plan { transition: background 0.22s; }
.trio > div:hover, .plan:hover { background: #fbfbf9; }

.cmp tbody tr { transition: background 0.18s; }
.cmp tbody tr:hover { background: #fbfaf7; }

.speclist li { transition: color 0.18s; }
.speclist li:hover span:last-child { color: var(--ink); }

.postlist a { transition: padding-left 0.24s cubic-bezier(0.22, 0.7, 0.25, 1); }
.postlist a:hover { padding-left: var(--s-2); }

/* The unit photo was a small object adrift in a large panel. */
.unit-shot img { max-width: 560px; transition: transform 0.5s cubic-bezier(0.22, 0.7, 0.25, 1); }
.unit-shot:hover img { transform: scale(1.02); }

@media (prefers-reduced-motion: reduce) {
.qa:hover, .unit-shot:hover img { transform: none; }
}
.unit-shot { background: #ffffff; border: 1px solid var(--rule-panel); }

/* The unit shot keeps its white ground — that is what the product was
 * photographed on, and it is the only panel on the page that is a window
 * rather than a plate. */
.unit-shot { background: #fff; border: 1px solid var(--rule); }

/* --- performance ----------------------------------------------------------- *
 * The Mac Studio pattern: a measure picker set in the same large type as the
 * claim, then bars that grow on arrival. Borrowed because it is the right
 * shape for the argument — three configurations, one of them ours, one number
 * each — not because it is Apple's. */

#performance { padding: var(--s-7) 0; }

.perf-tabs {
  margin-top: var(--s-3);
  font-family: var(--disp);
  font-weight: 700;
  font-size: var(--t-3xl);
  letter-spacing: -0.032em;
  line-height: 1.08;
  display: flex;
  flex-wrap: wrap;
  gap: 0 12px;
  align-items: baseline;
}
.perf-tabs button {
  font: inherit; letter-spacing: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--steel);
  transition: color 0.2s;
}
.perf-tabs button[aria-selected="true"] { color: var(--ink); }
.perf-tabs button:hover { color: var(--ink); }
.perf-tabs button[aria-selected="true"]:hover { color: var(--ink); }
.perf-sep { color: var(--rule); font-family: var(--disp); font-weight: 700; font-size: var(--t-3xl); }

.perf-claim {
  margin-top: var(--s-4);
  font-size: var(--t-lg);
  font-weight: 400;
  color: var(--steel);
  letter-spacing: 0;
  line-height: 1.55;
  max-width: 38rem;
}

.chart { margin-top: var(--s-5); }

.bar-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "track val" "name val";
  align-items: center;
  column-gap: var(--s-4);
  padding: var(--s-3) 0 var(--s-4);
}
.bar-track {
  grid-area: track;
  height: 10px;
  background: transparent;
}
.bar-track i {
  display: block; height: 100%; background: #c9c8c2;
  width: var(--w);
}
/* Only collapse the bars when the observer is confirmed to be running, so a
 * reader without JS or with reduced motion sees the finished chart. */
.will-reveal .chart .bar-track i { width: 0; }
.will-reveal .chart.shown .bar-track i {
  animation: grow-bar 1.05s cubic-bezier(0.22, 0.75, 0.2, 1) var(--d, 0s) forwards;
}
@keyframes grow-bar { from { width: 0; } to { width: var(--w); } }
.is-us .bar-track i { background: var(--sig); }
.bar-name { grid-area: name; margin-top: var(--s-1); font-size: var(--t-md); color: var(--steel); }
.is-us .bar-name { color: var(--ink); font-weight: 600; }
.bar-val {
  grid-area: val;
  font-family: var(--disp); font-weight: 700;
  font-size: var(--t-2xl); letter-spacing: -0.034em;
  color: #a8a7a1; line-height: 1;
}
.is-us .bar-val { color: var(--sig-text); }

@media (max-width: 680px) {
.perf-tabs, .perf-sep { font-size: var(--t-2xl); }
  .bar-val { font-size: var(--t-xl); }
}
@media (prefers-reduced-motion: reduce) {
.bar-track i { animation: none; width: var(--w); }
}

/* --- one styling, applied backwards through the page ----------------------- *
 * The performance section works because it is type and rules on open page. The
 * sections above it were bordered cards inside bordered grids, which read as a
 * form rather than an argument. Boxes off; hairlines and space instead. */

.trio, .trio.duo {
  border: 0;
  background: transparent;
  border-radius: 0;
  gap: clamp(28px, 4vw, 64px);
}
.trio > div {
  padding: var(--s-4) 0 0;
  border-right: 0;
  border-top: 1px solid var(--ink);
}
.trio > div:last-child { border-right: 0; }
.trio h3 { font-size: var(--t-xl); margin: var(--s-2) 0 var(--s-2); }
.trio p { font-size: var(--t-md); }
@media (max-width: 900px) {
.trio > div { border-bottom: 0; border-top: 1px solid var(--ink); padding-bottom: 0; }
}

.plans {
  border: 0; background: transparent; border-radius: 0;
  gap: clamp(28px, 4vw, 64px);
}
.plan { padding: var(--s-4) 0 0; border-right: 0; border-top: 1px solid var(--ink); }
.plan:last-child { border-right: 0; }
@media (max-width: 860px) {
.plan { border-bottom: 0; border-top: 1px solid var(--ink); }
}

/* The comparison table is the same argument as the chart — three columns, one
 * of them ours — so it gets the chart's emphasis rather than a table's. */
.cmp { border: 0; background: transparent; }
.cmp thead th { background: transparent; padding-left: 0; }
.cmp thead th.us { color: var(--sig-text); }
.cmp th, .cmp td { padding-left: 0; }
.cmp tbody th { font-size: var(--t-md); }
.cmp .us { box-shadow: none; color: var(--ink); font-weight: 600; padding-left: var(--s-3); position: relative; }
.cmp .us::before {
  content: ""; position: absolute; left: 0; top: 12px; bottom: 12px;
  width: 2px; background: var(--sig);
}
.cmp thead th.us { padding-left: var(--s-3); }
.cmp tbody tr:hover { background: transparent; }
.cmp tbody tr:hover .us { background: #fff6f1; }

/* Section headings all sit on the same step now. Several were one-off sizes. */
.sec-head p { font-size: var(--t-lg); }

/* The answer cards keep their borders — they are quoted screens, and a screen
 * with no edge stops reading as a screen. They lose the drop shadow instead,
 * which was the only soft thing left on the page. */
.qa { box-shadow: none; }
.qa:hover { box-shadow: none; border-color: var(--ink); transform: translateY(-2px); }

/* --- explain, reworked ----------------------------------------------------- *
 * Claim first, evidence beside it, detail underneath. The figures drop their
 * ink plate and adopt the chart's grammar — big type over a hairline, nothing
 * filled — because that plate was the last box left on the page. */

.explain-grid .explain { max-width: 38rem; }

.explain h2 { margin-top: var(--s-3); }

.claim {
  margin-top: var(--s-4);
  font-family: var(--disp);
  font-weight: 700;
  font-size: var(--t-xl);
  letter-spacing: -0.026em;
  line-height: 1.25;
  color: var(--ink);
  max-width: 30rem;
}
.explain .lede { margin-top: var(--s-3); font-size: var(--t-md); }
.lede-quiet { margin-top: var(--s-4); font-size: var(--t-md); color: var(--steel); }

.figures { padding-top: var(--s-1); }

/* Under the suite the same four facts are a strip, not a column. .fig was
 * built to sit in a narrow column beside body copy, where stacking is right;
 * at full width that stacking turned four facts into a screen and a half and
 * made the page longer than before it was cut. */
#suite .figures {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(20px, 3vw, 44px);
  margin-top: var(--s-5);
  padding-top: 0;
}
#suite .fig { padding: var(--s-3) 0 0; border-top: 1px solid var(--rule); }
#suite .fig:first-child { padding-top: var(--s-3); border-top: 1px solid var(--rule); }
#suite .fig-n { font-size: var(--t-xl); }
#suite .fig-l { font-size: var(--t-xs); }
@media (max-width: 1080px) {
#suite .figures { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 700px)  {
#suite .figures { grid-template-columns: 1fr; }
}
.fig { padding: var(--s-4) 0; border-top: 1px solid var(--ink); position: relative; }
.fig:first-child { padding-top: 0; border-top: 0; }
.fig-n {
  font-family: var(--disp); font-weight: 700;
  font-size: var(--t-2xl); letter-spacing: -0.034em; line-height: 1;
  color: var(--ink);
}
.fig-n small { font-size: 0.46em; font-weight: 500; letter-spacing: 0; }
.fig-l {
  margin-top: var(--s-2); font-size: var(--t-xs);
  color: var(--steel); line-height: 1.5; max-width: 26rem;
}

/* The accent arrives on approach rather than sitting on one arbitrary figure —
 * there is no "ours" here to mark, so a permanent orange would be noise. */
.fig::after {
  content: ""; position: absolute; left: 0; top: -1px;
  width: 0; height: 1px; background: var(--sig);
  transition: width 0.4s cubic-bezier(0.22, 0.7, 0.25, 1);
}
.fig:hover::after { width: 100%; }
.fig:first-child::after { display: none; }
.fig-n, .fig-l { transition: color 0.2s; }

@media (max-width: 940px) {
.figures { padding-top: 0; }
}
@media (prefers-reduced-motion: reduce) {
.fig::after { transition: none; }
}

/* --- ask: sticky claim, scrolling answers ---------------------------------- *
 * The three cards used to sit in a row and the fourth dropped awkwardly onto a
 * second line. As a column against a pinned claim they read as a stream of
 * questions arriving, which is what the product actually feels like. */

.ask-split {
  display: grid;
  grid-template-columns: 0.85fr 1fr;
  gap: clamp(32px, 6vw, 104px);
  align-items: start;
}
.ask-side {
  position: sticky;
  top: clamp(48px, 12vh, 120px);
}
.ask-side h2 { font-size: var(--t-3xl); margin-top: var(--s-3); }
.ask-side > p { margin-top: var(--s-3); font-size: var(--t-lg); color: var(--steel); }
.ask-note { font-size: var(--t-md) !important; margin-top: var(--s-4) !important; }

.ask-stream { display: flex; flex-direction: column; gap: clamp(20px, 3vw, 40px); }
.ask-stream .qa { max-width: none; }

/* Scroll-linked, so a card is at full strength only while it is the one being
 * read, and dims on the way in and on the way out. Native scroll timelines
 * rather than an observer: the effect is a function of position, not of a
 * threshold being crossed, and an observer can only approximate that. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 901px) {
    .ask-stream .qa {
      animation: pass-through linear both;
      animation-timeline: view();
      animation-range: entry 8% exit 92%;
    }
    @keyframes pass-through {
      0%   { opacity: 0; transform: translateY(28px) scale(0.985); }
      24%  { opacity: 1; transform: none; }
      74%  { opacity: 1; transform: none; }
      100% { opacity: 0; transform: translateY(-28px) scale(0.985); }
    }
  }
}

@media (max-width: 900px) {
.ask-split { grid-template-columns: 1fr; }
  .ask-side { position: static; }
}

/* --- real screenshots ------------------------------------------------------ *
 * Cropped by the frame rather than fitted inside it. A UI shrunk to fit reads
 * as a thumbnail of something else; one held at a legible scale and cut off by
 * the edge reads as a window onto software that carries on past it. Anchored
 * top-left because that is where both of these interfaces put the thing worth
 * seeing. */

/* Screenshots drift as they pass, which keeps a static image from reading as a
 * dead rectangle. Scroll-linked rather than a one-shot reveal, so the motion
 * tracks the reader instead of firing once and stopping. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 901px) {
    .sw-shots img {
      animation: shot-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes shot-drift {
      from { transform: translateY(0); }
      to   { transform: translateY(-14%); }
    }
  }
}

/* A photograph the system actually holds, rather than a dot-grid standing in
 * for one. Captioned in mono like a filename, because that is what it is. */
.qa-shot { margin: 0; position: relative; border-bottom: 1px solid var(--rule); background: var(--panel); }
.qa-shot img { display: block; width: 100%; height: auto; }
.qa-shot figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 8px 16px;
  font-family: var(--mono); font-size: 10.5px; color: #fff;
  background: linear-gradient(to top, rgba(11, 12, 11, 0.72), rgba(11, 12, 11, 0));
}

/* The refund line sits under the two plans rather than inside one: it applies
 * to the whole arrangement, and a guarantee in a column reads as a footnote to
 * that column only. */
/* --- the guarantee ---------------------------------------------------------- *
 * It was grey body text under the button: the single strongest thing on the
 * page, set as a footnote. Given a mark, a rule in the accent and its own
 * ground so it reads as an offer rather than small print. */

.guarantee h3 {
  font-size: var(--t-lg);
  letter-spacing: -0.02em;
  line-height: 1.25;
}

/* The nameplate is a tall portrait crop and was running the card to twice the
 * height of its neighbours. Cropped to a band instead — the plate's header and
 * first rows are what identify it; the rest is read by OCR, not by the reader. */
.qa-shot { height: clamp(150px, 15vw, 200px); overflow: hidden; }
.qa-shot img { height: 100%; object-fit: cover; object-position: 50% 22%; }

/* --- specifications -------------------------------------------------------- *
 * Framework's spec-page pattern: label left, value right, hairline between,
 * grouped under plain headings. It works because a spec sheet is read by
 * scanning down one column for the row you came for, and a table with six
 * columns of prose defeats that. */

.spec-head { padding: var(--s-7) 0 var(--s-5); max-width: 46rem; }
.spec-head h1 { font-size: var(--t-4xl); margin-top: var(--s-3); }
.spec-head p { margin-top: var(--s-3); font-size: var(--t-lg); color: var(--steel); }

.spec-body { padding-bottom: var(--s-7); }

.spec-group {
  display: grid;
  grid-template-columns: 0.62fr 1fr;
  gap: clamp(24px, 5vw, 88px);
  align-items: start;
  padding: 0 0 var(--s-7);
}
.spec-label { position: sticky; top: clamp(32px, 10vh, 96px); }
.spec-group h2 { font-size: var(--t-xl); }
.spec-content { max-width: 52rem; border-top: 1px solid var(--ink); padding-top: var(--s-2); }
@media (max-width: 860px) {
.spec-group { grid-template-columns: 1fr; gap: var(--s-2); padding-bottom: var(--s-6); }
  .spec-label { position: static; }
}
.spec-note {
  margin-top: var(--s-3);
  font-size: var(--t-md);
  color: var(--steel);
  max-width: 46rem;
  line-height: 1.6;
}

.spec-rows { margin: 0; padding: 0; }
/* Three columns: what it is, Mini, Scale. A value that spans the last two
 * means the two appliances do not differ on that row, which is most of the
 * page — the software and the network behaviour are the same unit of work,
 * and only the box changes. */
.spec-rows > div {
  display: grid;
  grid-template-columns: 13rem 1fr 1fr;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
}
/* A shared value spans both columns, and says so. Spanning alone was not
 * enough: a short one like "qwen2.5:3b" stops before the Scale column starts
 * and reads as Mini's value with Scale's left blank. */
.dd-both { grid-column: 2 / 4; position: relative; padding-right: 4.5rem; }
.dd-both::after {
  content: "both";
  position: absolute; right: 0; top: 3px;
  font-family: var(--mono); font-size: var(--t-mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel);
}
@media (max-width: 720px) {
  .dd-both { padding-right: 0; }
  .dd-both::after { position: static; display: block; margin-top: 6px; }
}
/* .spec-cols, not .spec-head: that name was already the page's intro block,
 * and reusing it drew a rule under the standfirst. */
.spec-cols {
  padding-bottom: 10px !important;
  border-bottom: 1px solid var(--ink) !important;
}
.spec-cols dd {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
}
.spec-rows > div:last-child { border-bottom: 0; }
.spec-rows dt { font-size: var(--t-md); font-weight: 600; }
.spec-rows dd { margin: 0; font-size: var(--t-md); }
.dd-sub {
  display: block;
  margin-top: 6px;
  font-size: var(--t-xs);
  color: var(--steel);
  line-height: 1.55;
  max-width: 44rem;
}
@media (max-width: 720px) {
.spec-rows > div { grid-template-columns: 1fr; gap: 4px; }
}

.spec-table { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
.spec-table th, .spec-table td {
  text-align: left; padding: var(--s-2) var(--s-3) var(--s-2) 0;
  border-bottom: 1px solid var(--rule); font-weight: 400;
}
.spec-table thead th {
  font-family: var(--mono); font-size: var(--t-mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel);
}
.spec-table tbody th { font-weight: 600; }
.spec-table .row-us th, .spec-table .row-us td { color: var(--ink); font-weight: 600; }
.spec-table .row-us th { box-shadow: inset 2px 0 0 var(--sig); padding-left: var(--s-3); }

/* A stat caption that is also a link should not shout about it — the underline
 * arrives on approach, like the nav. */
.fig-link { text-decoration: none; border-bottom: 1px solid transparent; transition: border-color 0.2s, color 0.2s; }
.fig-link:hover { color: var(--ink); border-bottom-color: var(--sig); }

.spec-cta h2 { border-bottom-color: var(--rule); }

/* A forthcoming capability has to be legible as forthcoming at a glance, or a
 * reader takes the row as present tense and uploads a file that gets refused. */
.soon {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sig-text);
  border: 1px solid var(--sig);
  vertical-align: 2px;
}

/* The label column keeps its own measure so a long group name wraps rather
 * than pushing the rows around. */
.spec-label h2 { max-width: 14rem; }
.spec-cta .spec-content { border-top-color: var(--rule); }

/* A spec row that leads somewhere should look like a value first and a link
 * second — the list is read as a summary, not as navigation. */
.spec-jump {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--steel);
  text-align: right; font-weight: 400; text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.18s, border-color 0.18s;
}
.spec-jump:hover { color: var(--ink); border-bottom-color: var(--sig); }

/* --- component reference ---------------------------------------------------- *
 * Not part of the marketing site; noindex'd. Each entry renders live from the
 * same stylesheet the site uses, so a pattern that breaks here has broken
 * everywhere. */

.cmp-body { padding-bottom: var(--s-7); }
.cmp-group {
  font-size: var(--t-2xl);
  margin: var(--s-7) 0 var(--s-4);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--ink);
}
.cmp-item {
  display: grid;
  grid-template-columns: 0.5fr 1fr;
  gap: clamp(24px, 4vw, 64px);
  align-items: start;
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--rule);
}
.cmp-label h3 { font-size: var(--t-lg); }
.cmp-label p { margin-top: var(--s-1); font-size: var(--t-xs); color: var(--steel); line-height: 1.55; }
.cmp-label code { font-family: var(--mono); font-size: 0.92em; }
/* Where the markup came from. The reference extracts rather than transcribes,
 * so the origin is the useful thing to print: it is also the fix instruction. */
.cmp-origin {
  margin-top: var(--s-2);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.02em;
  color: var(--steel);
  opacity: 0.75;
}
.cmp-origin code { font-size: 1em; }

/* The demo column: a live render above the markup that produced it. Constrains
 * the extracted component so a full-bleed section does not escape the column. */
.cmp-demo { min-width: 0; }
.cmp-demo .wrap { padding-left: 0; padding-right: 0; }

.cmp-render {
  padding: var(--s-4);
  overflow-x: auto;
  border: 1px dashed var(--rule);
  background: var(--card);
}
.cmp-code {
  margin: var(--s-2) 0 0;
  padding: var(--s-3);
  overflow-x: auto;
  background: var(--panel);
  color: #d8dbd6;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.65;
}
@media (max-width: 860px) {
.cmp-item { grid-template-columns: 1fr; gap: var(--s-3); }
}

/* --- sticky navbar ---------------------------------------------------------- *
 * Same markup on every page. Sticky matters most on the datasheet, where the
 * reader is thirty spec rows deep and the reason they came was to ask for one. */

.navbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--rule);
}
.navbar .nav { border-bottom: 0; }
.navbar .nav-in { padding-top: 14px; padding-bottom: 14px; gap: 26px; }
.nav-link[aria-current="page"] { color: var(--ink); }
.nav-link[aria-current="page"]::after { right: 0; }
@media (max-width: 940px) {
.navbar .nav-link { display: none; }
  .navbar .nav-in { gap: 12px; }
}

/* --- request form ----------------------------------------------------------- */

.req-body { padding-bottom: var(--s-7); }
.req-group {
  display: grid;
  grid-template-columns: 0.62fr 1fr;
  gap: clamp(24px, 5vw, 88px);
  align-items: start;
  padding: var(--s-5) 0;
  border-top: 1px solid var(--rule);
}
.req-group:first-child { border-top: 1px solid var(--ink); }
.req-label h2 { font-size: var(--t-xl); }
.req-label p { margin-top: var(--s-1); font-size: var(--t-xs); color: var(--steel); line-height: 1.55; }

.req-fields { display: flex; flex-direction: column; gap: var(--s-3); max-width: 40rem; }
.req-fields label {
  display: block;
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--ink);
}
.req-fields input,
.req-fields select,
.req-fields textarea {
  display: block;
  width: 100%;
  margin-top: 7px;
  padding: 11px 13px;
  font-family: var(--font);
  font-size: var(--t-md);
  font-weight: 400;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 0;
  transition: border-color 0.16s;
}
.req-fields textarea { resize: vertical; line-height: 1.55; }
.req-fields input:focus,
.req-fields select:focus,
.req-fields textarea:focus { outline: none; border-color: var(--sig); }

/* Square like everything else, and its own chevron: the native one on macOS
 * comes with a rounded well that reintroduces the corner radius. */
.req-fields select {
  appearance: none;
  cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--steel) 50%),
                    linear-gradient(135deg, var(--steel) 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 12px) 55%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 38px;
}
.req-fields ::placeholder { color: var(--steel); }
.req-note { margin-top: var(--s-3); font-size: var(--t-xs); color: var(--steel); line-height: 1.6; }

@media (max-width: 860px) {
.req-group { grid-template-columns: 1fr; gap: var(--s-3); }
}

/* Honeypot: off-screen rather than display:none, because some bots skip
 * anything a stylesheet has hidden outright. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.req-status { margin-top: var(--s-2); font-size: var(--t-xs); color: var(--steel); min-height: 1.2em; }
.req-status.is-bad { color: var(--sig-text); }
.req-done h2 { font-size: var(--t-xl); }
.req-done p { margin-top: var(--s-3); font-size: var(--t-md); color: var(--steel); max-width: 40rem; }

/* The appliance at product-shot scale. Full bleed, the image bled off the
 * bottom so the box reads as larger than the band holding it, and the words
 * sitting on the ground rather than over the machine. */

/* Pricing, centred on the dark band. The number carries the section; the
 * inclusions are chips because a chip is read at a glance. */
.price-band { text-align: center; }
.price-band .eyebrow { color: var(--sig); }
.price-big {
  font-family: var(--disp);
  font-weight: 800;
  font-size: clamp(56px, 11vw, 124px);
  letter-spacing: -0.05em;
  line-height: 0.9;
  margin-top: var(--s-3);
  color: #fff;
}
.price-sub {
  margin-top: var(--s-3);
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--steel-dark);
}
.price-ctas {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--s-1);
  margin-top: var(--s-4);
}
.btn-inv { background: #fff; color: var(--ink); border-color: #fff; }
.btn-inv:hover { background: var(--sig); border-color: var(--sig); color: #fff; }
.btn-outline { background: transparent; color: #fff; border-color: var(--rule-panel); }
.btn-outline:hover { border-color: #fff; }

.price-why {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 5vw, 72px);
  text-align: left;
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule-panel);
}
.price-why h3 { font-size: var(--t-lg); color: #fff; letter-spacing: -0.02em; }
.price-why p { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--steel-dark); }
@media (max-width: 760px) {
.price-why { grid-template-columns: 1fr; }
}

/* The software section: shots on one side, words on the other.
 *
 * It previously stacked a screenshot under each of two text blocks, which put
 * two small images at two different heights and read as a patchwork by
 * accident rather than on purpose. Sizes come from the grid and aspect-ratio
 * here, never from a percentage width tuned to one column, which is the
 * mistake that cropped .shot to its top-left corner. */
.sw-split {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(28px, 4vw, 72px);
  /* Top, not centre. The shots column is inevitably taller than two short
   * paragraphs, and centring floated the words in the middle of a screen of
   * white with nothing to line up against. */
  align-items: start;
}
.sw-shots {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: clamp(10px, 1.2vw, 16px);
}
.sw-shots figure {
  margin: 0;
  border: 1px solid var(--rule);
  background: var(--card);
  overflow: hidden;
}
.sw-shots img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top left; }
/* The chat across the top, the two admin tabs beneath it. Three shots in a
 * single column stacked to about 1250px against 300px of text, which centred
 * the words against a screen of nothing. Two rows instead of three, and the
 * columns land close enough in height to sit beside each other. */
.sw-a { grid-column: 1 / 7; aspect-ratio: 16 / 10; }
.sw-b { grid-column: 1 / 4; aspect-ratio: 4 / 3; }
.sw-c { grid-column: 4 / 7; aspect-ratio: 4 / 3; }

.sw-say { display: grid; gap: var(--s-4); }
.sw-say h3 { margin-top: 6px; font-size: var(--t-lg); letter-spacing: -0.02em; }
.sw-say p { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--steel); }

/* Four use cases, each shown answering something.
 *
 * The dark block is called a panel rather than a card on purpose: the
 * contrast guard judges literal colours against the page, and exempts
 * selectors that say they are painting on a dark ground. Light text here is
 * correct, and the name is how the test knows that. */
.uc-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 3.5vw, 64px);
}
.uc { display: flex; flex-direction: column; }
.uc-e { color: var(--sig-text); }
.uc h3 { margin-top: 8px; font-size: var(--t-xl); letter-spacing: -0.02em; }
.uc > p { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--steel); max-width: 34rem; }
.uc-note {
  margin-top: var(--s-3);
  font-family: var(--mono);
  font-size: var(--t-mono);
  color: var(--steel);
}

.uc-panel {
  margin-top: var(--s-3);
  background: var(--ink);
  padding: clamp(20px, 2.2vw, 30px);
  flex: 1;
  display: flex;
  flex-direction: column;
}
.uc-panel .uc-q { font-weight: 650; color: #fff; font-size: var(--t-md); }
.uc-panel .uc-a { margin-top: var(--s-2); font-size: var(--t-sm); color: #d6d8d4; }
.uc-panel .uc-a strong { color: #fff; }

.uc-panel .uc-tb {
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--rule-panel);
  font-family: var(--mono);
  font-size: var(--t-mono);
}
.uc-panel .uc-tb > div { display: flex; justify-content: space-between; gap: 16px; padding: 3px 0; }
.uc-panel .uc-tb dt { color: var(--steel-dark); }
.uc-panel .uc-tb dd { margin: 0; color: #d6d8d4; text-align: right; }

.uc-panel .uc-cite {
  margin-top: var(--s-3);
  align-self: flex-start;
  border: 1px solid var(--sig);
  color: var(--sig);
  padding: 5px 9px;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.06em;
}

@media (max-width: 860px) {
.uc-grid { grid-template-columns: 1fr; }
}

/* The investment band, and the growth figure on it.
 *
 * The bars carry no scale and no numbers on purpose: they show that what the
 * plant teaches keeps growing while what the model arrived with does not, and
 * that is a property of the product rather than a measurement. */
.sig-e { color: var(--sig); }
.invest-split {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(32px, 5vw, 88px);
  align-items: center;
}
.invest-h {
  margin-top: var(--s-3);
  color: #fff;
  font-size: var(--t-3xl);
  letter-spacing: -0.035em;
  line-height: 1.02;
}
.invest-p { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--steel-dark); max-width: 34rem; }

.growth { margin: 0; border: 1px solid var(--rule-panel); padding: clamp(20px, 2.4vw, 32px); }
.growth-head {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px;
  font-family: var(--mono); font-size: var(--t-mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel-dark);
}
.growth-key { display: flex; align-items: center; gap: 8px; }
.growth-key i { width: 9px; height: 9px; display: inline-block; margin-left: 10px; }
.k-base { background: #3a3d39; }
.k-add { background: var(--sig); }

.growth-bars {
  margin-top: var(--s-4);
  display: grid; grid-template-columns: repeat(10, 1fr); gap: clamp(5px, 0.8vw, 11px);
  align-items: end;
}
.gb { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }
.gb-stack { display: flex; flex-direction: column; justify-content: flex-end; height: clamp(130px, 17vw, 210px); }
.gb-add { background: var(--sig); }
.gb-base { height: 34px; background: #3a3d39; flex: none; }
.gb span {
  font-family: var(--mono); font-size: var(--t-mono);
  color: var(--steel-dark); text-align: center;
}
.growth-note { margin-top: var(--s-3); font-size: var(--t-xs); color: var(--steel-dark); }

.seg { display: flex; border: 1px solid var(--rule); background: #fff; }

/* The dimension drawing fills its column on white.
 *
 * .unit-shot was built for a photograph of the unit: a grey panel, generous
 * padding, the image capped at 560px and multiplied into the panel so the
 * product sat in a frame. Every one of those is wrong for a line drawing —
 * the cap made it small, the panel put a grey box around it, and multiply
 * dirtied the white it is drawn on. It gets none of them.
 *
 * A class rather than :has(), because .unit-shot img is restyled further down
 * the file and would win against it anyway. */
.unit-dims {
  border: 0;
  /* Transparent, not white. It was #fff when the drawing arrived on a white
   * ground; now every product figure is saved on --paper, so painting the
   * figure at all just put a white strip behind the caption. */
  background: none;
  padding: 0;
  align-items: stretch;
}
.unit-dims img {
  width: 100%;
  max-width: none;
  mix-blend-mode: normal;
}
.unit-dims:hover img { transform: none; }

/* The ports strip under the unit. */
.unit-ports { margin: var(--s-5) 0 0; }
.unit-ports img { display: block; width: 100%; height: auto; }
.unit-ports figcaption,
.unit-shot figcaption {
  margin-top: var(--s-2);
  font-family: var(--mono); font-size: var(--t-mono); color: var(--steel);
}

@media (max-width: 900px) {
/* Restored after a sweep removed it. The rule read
   * `.invest-split, .size-split { ... }`, and removing the dead half of a
   * grouped selector took the live half with it, so the band never collapsed
   * and its chart hung 120px off the right of a phone. */
  .invest-split { grid-template-columns: 1fr; }

  /* Ten bars in a 350px column is a 19px bar with a label under it. Five
   * reads; the shape is the point, not the resolution. */
  .growth-bars { grid-template-columns: repeat(5, 1fr); }
  .gb:nth-child(even) { display: none; }
  .growth-head { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* The one place the homepage mentions the other product. Deliberately a
 * single row rather than a second pricing table: the page is arguing that an
 * on-premise appliance is a real idea, and a SKU comparison in the middle of
 * that argument is a different conversation. */
.mini-band {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(20px, 4vw, 56px);
  border: 1px solid var(--rule);
  background: var(--card);
  padding: clamp(24px, 3vw, 40px);
}
.mini-band h2 { margin-top: 8px; font-size: clamp(22px, 2.6vw, 32px); letter-spacing: -0.02em; }
.mini-band p { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--steel); max-width: 46rem; }
.mini-band .btn { flex: none; }
@media (max-width: 760px) {
.mini-band { flex-direction: column; align-items: flex-start; }
}

/* Mini's hero carries no photograph: its chassis is not chosen yet, and the
 * only appliance images we have are of Scale's box. */
.mini-hero { max-width: 46rem; padding: clamp(40px, 7vw, 96px) 0; }

/* The hero's second product. A line, not a third button: two buttons are a
 * choice and three are a menu, and the primary action here stays the quote. */
.hero-alt {
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--steel);
}
.hero-alt a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--sig);
}
.hero-alt a:hover { color: var(--sig-text); }


/* Which appliance. Shown only when the reader did not arrive from a product
 * button, which is every link from the navbar on an editorial page. */
.pick { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); margin-top: var(--s-4); }
.pick-b {
  text-align: left; cursor: pointer;
  border: 1px solid var(--rule); background: var(--card);
  padding: clamp(14px, 1.8vw, 20px);
  font: inherit; color: var(--ink);
}
.pick-b:hover { border-color: var(--ink); }
.pick-b.is-on { border-color: var(--sig); box-shadow: inset 0 0 0 1px var(--sig); }
.pick-b b { display: block; font-size: var(--t-md); }
.pick-b span { display: block; margin-top: 4px; font-family: var(--mono); font-size: var(--t-mono); color: var(--sig-text); }
.pick-b em { display: block; margin-top: 8px; font-style: normal; font-size: var(--t-xs); color: var(--steel); }
@media (max-width: 620px) { .pick { grid-template-columns: 1fr; } }

/* --- datasheet download ------------------------------------------------------ *
 * One field on one line, above the specifications. A reader who came for a
 * torque figure will trade an address for a PDF and will not fill in a form. */

.get-pdf {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
  padding: var(--s-4) 0 var(--s-5);
  border-top: 1px solid var(--rule);
}
.get-pdf-say h2 { font-size: var(--t-xl); letter-spacing: -0.02em; }
.get-pdf-say p { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--steel); }

.get-pdf-form { display: grid; grid-template-columns: 1fr auto; gap: var(--s-2); align-items: start; }
.get-pdf-form input[type="email"] {
  width: 100%;
  height: 44px;
  padding: 0 14px;
  font: 400 var(--t-md)/1 var(--font);
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 0;
}
.get-pdf-form input[type="email"]:focus { outline: none; border-color: var(--sig); }
.get-pdf-form input::placeholder { color: var(--steel); }
.get-pdf-form .btn { height: 44px; line-height: 42px; padding: 0 18px; }
.get-pdf-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--t-xs);
  color: var(--steel);
  line-height: 1.6;
}

/* Present for a screen reader, absent for everyone else: the placeholder
 * carries the label visually, and a placeholder is not a label. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 760px) {
.get-pdf { grid-template-columns: 1fr; gap: var(--s-3); }
  .get-pdf-form { grid-template-columns: 1fr; }
}

/* --- quote request ---------------------------------------------------------- *
 * The page is a request for a specific thing, not an open contact box, so it
 * carries the shape of an order: what happens next, what it costs, and an
 * address block. Fields that belong on one line share one. */

.req-legend {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--steel);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--ink);
}
.req-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3); }
@media (max-width: 520px) {
.req-row { grid-template-columns: 1fr; }
}

/* Marks the two fields that are genuinely optional. Everything else is
 * required, and saying so once per field beats an asterisk legend. */
.req-opt {
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--steel);
}
.req-opt::before { content: "\2014\00a0"; }

.flow-price {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
}
.flow-price b { display: block; font-size: var(--t-2xl); letter-spacing: -0.02em; }
.flow-price b small { font-size: 0.38em; font-weight: 500; letter-spacing: 0; color: var(--steel); }
.flow-price span {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--t-xs);
  color: var(--steel);
  line-height: 1.6;
}

/* --- contact ---------------------------------------------------------------- *
 * Same split as the ask section and the spec groups: what the page is on the
 * left, what you do about it on the right. Pinned, because a short form leaves
 * the left column empty otherwise on a tall screen. */

.contact-split {
  display: grid;
  grid-template-columns: 1fr 0.86fr;
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
  padding: var(--s-7) 0;
}
.contact-intro { position: sticky; top: clamp(96px, 16vh, 160px); }
.contact-intro h1 { font-size: var(--t-3xl); margin-top: var(--s-3); }
.contact-intro p { margin-top: var(--s-3); font-size: var(--t-lg); color: var(--steel); }
.contact-form .req-fields { max-width: none; }

@media (max-width: 900px) {
.contact-split {
    grid-template-columns: 1fr;
    gap: var(--s-5);
    padding-top: var(--s-6);
    padding-bottom: var(--s-6);
  }
  .contact-intro { position: static; }
}

/* The resources index is a narrow column, so its head needs less top padding
 * than a full-width page and the list needs air under it. */
.wrap.narrow .spec-head { padding: var(--s-6) 0 var(--s-5); max-width: none; }
.wrap.narrow .spec-head h1 { font-size: var(--t-3xl); }
.wrap.narrow .postlist { margin-bottom: var(--s-7); }

/* --- pricing, single plan --------------------------------------------------- *
 * Two line items invited the reader to add them up and compare the total to a
 * server they could buy outright. One number, with the hardware inside it,
 * changes the question being asked. */

.price-includes li {
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--t-md);
  color: var(--steel);
  line-height: 1.6;
}
.price-includes b { display: block; color: var(--ink); font-weight: 600; margin-bottom: 3px; }

.price-why { margin-top: var(--s-5); }
.price-why h3 { font-size: var(--t-xl); letter-spacing: -0.026em; }
.price-why p {
  margin-top: var(--s-3);
  font-size: var(--t-md);
  color: var(--steel);
  line-height: 1.65;
}

/* --- site footer ------------------------------------------------------------ *
 * Four columns and a legal bar, identical on every page. Nothing in it is
 * invented: no address, no registered number, no jurisdiction. A footer is
 * exactly where a young business starts quietly making those up. */

.site-foot { border-top: 1px solid var(--ink); padding: var(--s-6) 0 var(--s-5); }

.foot-top {
  display: grid;
  grid-template-columns: 0.9fr 1.4fr;
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
}
.foot-brand .brand { font-size: 20px; }
.foot-tag {
  margin-top: var(--s-3);
  font-size: var(--t-xs);
  color: var(--steel);
  line-height: 1.6;
  max-width: 30rem;
}
.foot-note-small {
  margin-top: var(--s-2);
  font-size: var(--t-xs);
  color: var(--ink);
  font-weight: 600;
  max-width: 30rem;
}

.foot-links { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-4); }
.foot-links h2 {
  font-family: var(--mono);
  font-size: var(--t-mono);
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--steel);
  margin-bottom: var(--s-2);
}
.foot-links a {
  display: block;
  padding: 5px 0;
  font-size: var(--t-xs);
  color: var(--steel);
  text-decoration: none;
  transition: color 0.16s;
}
.foot-links a:hover { color: var(--ink); }

.foot-bottom {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-top: var(--s-6);
  padding-top: var(--s-3);
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs);
  color: var(--steel);
}

@media (max-width: 900px) {
.foot-top { grid-template-columns: 1fr; gap: var(--s-5); }
  .foot-links { grid-template-columns: 1fr 1fr; gap: var(--s-4) var(--s-3); }
}

/* --- mobile ------------------------------------------------------------------ *
 * The hero stayed two-column on a phone because .band.paper .showcase outranks
 * the .showcase media query and comes later in the file. Two 160px columns on a
 * 390px screen is not a layout. Stacked, product first: it is the thing being
 * sold and the only part that reads at a glance.
 *
 * Everything else here is subtraction. A page written to be read on a desk is
 * a wall on a phone, and a plant manager checking this on the floor is not
 * going to work through 900 words to find the price. */

@media (max-width: 760px) {

  /* Hero: stacked, and sized to the screen rather than to a desktop clamp. */
  .band.paper .showcase {
    grid-template-columns: 1fr;
    gap: var(--s-4);
    text-align: left;
  }
  /* The product sits at 72% of the image width — the shadow trails left — so
   * centring the image leaves the machine off to the right. Shift by the
   * measured offset to centre the thing rather than the file. */
  .band.paper .stage { justify-content: center; margin-left: 0; }
  .band.paper .appliance { transform: translateX(-11%); }
  .band.paper .appliance { height: min(38svh, 300px); }
  .hero-full { min-height: 0; padding: var(--s-4) 0 var(--s-6); }
  .band.paper h1 { font-size: clamp(34px, 11vw, 46px); }
  .band.paper .sub { margin-top: var(--s-3); font-size: var(--t-base); max-width: none; }
  .actions { margin-top: var(--s-4); }
  .actions .btn { flex: 1 1 auto; text-align: center; }

  /* Prose that earns its place on a desk does not earn it here. Measured per
   * section on a 390px screen: price 261 words, limits 191, unit 147. Those
   * three were two thirds of the page. Cut to the sentence that carries the
   * point; the desktop page and the datasheet still hold the argument. */
  .explain .lede { font-size: var(--t-md); }
  .ask-note { display: none; }
  /* Keep the tagline, drop the network claim: it is made three times
   * elsewhere and was standing in for the tagline once this was hidden. */
  .foot-note-small { display: none; }

  /* Pricing: the number, what it includes, and the refund. The essay on why
   * it is a subscription is a desk read. */
  .price-why p:nth-of-type(n + 2) { display: none; }

  /* Limits: four long items become four claims. The explanation after each
   * full stop is the part that can wait. */
  .nots li { font-size: var(--t-md); padding: var(--s-2) 0; }
  .nots li .why { display: none; }

  /* The unit's second paragraph and the bleed-card descriptions are both
   * elaboration on a heading that already says it. */
  .unit-sec .lead-sm + .lead-sm { display: none; }
  .bleed > p { display: none; }

  /* Bleed cards are a desktop gesture: on a phone the crop leaves a sliver. */
  .bleed { min-height: 0; }
  .bleed-img { min-height: 190px; }
  .bleed-bottom img { width: 118%; top: 0; }
  .bleed-wide img { width: 104%; }

  /* Sections were spaced for a 1500px canvas. */
  section, #inside, #performance,   .sec-head { margin-bottom: var(--s-4); }
  .spec-head { padding: var(--s-5) 0 var(--s-4); }

  /* Label and value side by side on a 390px screen means both wrap into each
   * other. Stack, and left-align the value under its label. */
  .speclist li { display: block; padding: var(--s-2) 0; }
  .speclist li span:first-child { display: block; font-size: var(--t-xs); color: var(--steel); }
  .speclist li span:last-child,
  .speclist li .spec-jump { display: block; text-align: left; margin-top: 3px; color: var(--ink); }

  /* Two 45%-width columns of link text is not a footer. */
  .foot-links { grid-template-columns: 1fr 1fr; }
  .foot-bottom { margin-top: var(--s-4); }
}

@media (max-width: 420px) {
.foot-links { grid-template-columns: 1fr; gap: var(--s-3); }
  .qa .a { font-size: var(--t-md); }
  .tb { grid-template-columns: 1fr; }
  .tb div { border-right: 0; border-bottom: 1px solid var(--rule); }
  .tb div:last-child { border-bottom: 0; }
}

/* A leading qualifier on a figure sits smaller and lighter than the number it
 * qualifies, or it reads as part of the number. */
.fig-n small:first-child {
  font-size: 0.42em;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--steel);
  margin-right: 2px;
}

/* --- performance on a phone --------------------------------------------------- *
 * The measure picker is two long labels with a slash between them. Inline, the
 * second wraps to two centre-ish lines against a left-aligned first, which
 * reads as broken rather than as a choice. Stacked, each is a line you can tap.
 *
 * The bars had desktop spacing and a value that floated against a two-line
 * label. Tighter, and the number pinned to the top of its row. */

@media (max-width: 760px) {
  /* Stacked at heading size, two tabs read as two headlines rather than a
   * choice, and the section stops matching every other one on the page. On a
   * phone they become a plain control under the eyebrow: small, left-aligned,
   * with the selected one underlined in the accent. */
  .perf-tabs {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    font-size: var(--t-lg);
    line-height: 1.3;
    margin-top: var(--s-2);
  }
  .perf-tabs button {
    display: block;
    text-align: left;
    width: auto;
    padding: 7px 0;
    font-weight: 600;
    border-bottom: 2px solid transparent;
  }
  .perf-tabs button[aria-selected="true"] { border-bottom-color: var(--sig); }
  .perf-sep { display: none; }

  .perf-claim { margin-top: var(--s-3); font-size: var(--t-md); }
  .chart { margin-top: var(--s-4); }

  .bar-row {
    grid-template-columns: 1fr auto;
    grid-template-areas: "track val" "name val";
    align-items: start;
    column-gap: var(--s-3);
    padding: var(--s-2) 0 var(--s-3);
  }
  .bar-val { font-size: var(--t-xl); line-height: 1.1; }
  .bar-name { font-size: var(--t-xs); margin-top: 6px; }
  .bar-track { height: 8px; }
}

/* One item left in the legal bar; space-between on a single child pushes it
 * nowhere useful. */
.foot-bottom:has(> p:only-child) { justify-content: flex-start; }

/* --- mobile menu -------------------------------------------------------------- *
 * <details> rather than a script: it opens, closes, takes focus and answers
 * Escape on its own, and the links are in the markup for a crawler whatever
 * the viewport. On desktop the summary is hidden and the panel is laid out
 * inline, so one piece of markup is a row of links there and a drop-down here. */

/* The panel is a flex row in its own right rather than display:contents.
 * Nesting two contents boxes meant .nav-in's gap never reached the links —
 * they sat 3px apart at every width, which only looked deliberate because the
 * labels are short. */
.nav-menu { display: contents; }
.nav-menu > summary { display: none; }
.nav-menu .nav-panel,
.nav-menu:not([open]) .nav-panel {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2vw, 30px);
}

@media (max-width: 940px) {
.nav-menu { display: block; position: relative; }

  .nav-menu > summary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin-right: 4px;
    cursor: pointer;
    list-style: none;
  }
  .nav-menu > summary::-webkit-details-marker { display: none; }

  /* Three lines drawn from one element, so there is nothing to keep in sync. */
  .burger, .burger::before, .burger::after {
    display: block;
    width: 19px;
    height: 2px;
    background: var(--ink);
    transition: transform 0.2s cubic-bezier(0.22, 0.7, 0.25, 1), opacity 0.15s;
  }
  .burger::before, .burger::after { content: ""; position: absolute; }
  .burger::before { transform: translateY(-6px); }
  .burger::after { transform: translateY(6px); }

  .nav-menu[open] > summary .burger { background: transparent; }
  .nav-menu[open] > summary .burger::before { transform: rotate(45deg); }
  .nav-menu[open] > summary .burger::after { transform: rotate(-45deg); }

  .nav-menu .nav-panel {
    display: block;
    position: absolute;
    top: calc(100% + 12px);
    right: -8px;
    min-width: 208px;
    padding: var(--s-2) 0;
    background: var(--card);
    border: 1px solid var(--ink);
    box-shadow: 0 24px 48px -32px rgba(11, 12, 11, 0.55);
    z-index: 30;
  }
  /* The links were display:none at this width for the desktop layout. */
  .nav-menu .nav-panel .nav-link {
    display: block;
    padding: 11px var(--s-3);
    font-size: var(--t-md);
    color: var(--ink);
  }
  .nav-menu .nav-panel .nav-link::after { display: none; }
  .nav-menu .nav-panel .nav-link[aria-current="page"] { color: var(--sig-text); }
  .nav-menu .nav-panel .nav-link:hover { background: var(--panel-tint, #f5f5f3); }
}

/* --- choice pills ------------------------------------------------------------- *
 * Replaces a <select>. Four options do not need a picker, and a native select
 * popup in a mobile viewport opens wherever the browser decides — which on a
 * narrow screen was nowhere near the field. These are always visible, one tap,
 * and keyboard-navigable as a radio group. */

.req-choice { border: 0; margin: 0; padding: 0; }
.req-choice legend {
  padding: 0;
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--ink);
}
.req-choice { display: flex; flex-wrap: wrap; gap: 8px; }
.req-choice legend { flex: 0 0 100%; margin-bottom: 9px; }
.req-choice label { display: inline-flex; cursor: pointer; }
.req-choice input { position: absolute; opacity: 0; width: 0; height: 0; }
.req-choice span {
  display: block;
  padding: 9px 14px;
  font-size: var(--t-md);
  color: var(--steel);
  background: var(--card);
  border: 1px solid var(--rule);
  transition: border-color 0.16s, color 0.16s;
}
.req-choice label:hover span { color: var(--ink); border-color: #cfcdc5; }
.req-choice input:checked + span { color: var(--ink); border-color: var(--ink); font-weight: 600; }
.req-choice input:focus-visible + span { outline: 2px solid var(--sig); outline-offset: 2px; }

/* The sticky column has a heading, two paragraphs and then a long silence
 * while four answers scroll past. That silence is the moment the reader has
 * just understood what it does, so it gets the ask. */
.ask-cta { margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--rule); }
.ask-cta p {
  margin-top: var(--s-3);
  font-size: var(--t-xs);
  color: var(--steel);
  line-height: 1.6;
  max-width: 26rem;
}
@media (max-width: 900px) {
.ask-cta { margin-top: var(--s-4); padding-top: var(--s-3); }
}
