/* Carvect Pro — marketing + account + admin.
 *
 * Light, but not timid. The page is white; the drama comes from two deep-blue
 * bands that bookend it — the hero at the top and the closing call below — with
 * the whole argument set on white between them. That keeps the contrast the
 * old graphite site had, without the guardedness of a black page.
 *
 * One blue family, three jobs: a deep navy (--deep) for the dark bands, a
 * slightly lighter navy (--ink) for headings on white, and a bright, clean blue
 * (--accent) for anything that wants to be noticed. Technical material —
 * versions, licence keys, seat counts, prices — and the navigation are set in
 * mono, which is where most of the machine-shop character comes from.
 *
 * Two ink colours, deliberately: --ink is the navy headings and navigation are
 * set in; --text is the softer slate body copy is set in. Running paragraphs in
 * the heading navy makes a page feel shouted.
 */

:root {
  --ground: #ffffff;        /* the page: white, and most of it */
  --ground-2: #f1f6fb;      /* the alternate band: white with a blue cast */
  --surface: #ffffff;       /* cards, panels, the price box */
  --paper: #ffffff;         /* text and rules ON the accent (buttons) */
  --paper-2: #dce8f2;

  --deep: #071f34;          /* the dark bands: hero, closing, footer */
  --deep-2: #113f66;        /* the lit end of those bands */
  --on-deep: #eaf2f8;       /* text on the dark */
  --on-deep-mute: #9db6c9;
  --on-deep-faint: #7f9bb0;

  --ink: #0c2f4c;           /* headings, brand, navigation */
  --text: #3b5262;          /* body copy */
  --mist: #5d7385;          /* secondary text */
  --faint: #8698a6;
  --line: rgba(12, 47, 76, 0.12);
  --line-strong: rgba(12, 47, 76, 0.22);
  --line-dark: rgba(234, 242, 248, 0.16);   /* hairlines on the dark bands */

  --accent: #1a7ae0;        /* the bright blue: eyebrows, rules, buttons */
  --accent-deep: #1567c0;   /* the accent under a pointer */
  --accent-lift: #6fb6ff;   /* the accent on a dark ground */
  --accent-soft: rgba(26, 122, 224, 0.09);
  --accent-line: rgba(26, 122, 224, 0.40);

  /* Companions to the blue, as on smepoint.com: one at a time, to say which
     stage or which family a thing belongs to -- Setup teal, Design violet,
     Manufacture coral, Preview amber; the toolpath board's 2D, carving and 3D
     columns sky, violet and amber. Never all at once except in the spectrum
     rule under the header. */
  --teal: #0d8f80;
  --sky: #1a7ae0;
  --violet: #7563e0;
  --coral: #e0573f;
  --amber: #d98a12;
  --teal-soft: #e7f6f3;
  --sky-soft: #eaf3fd;
  --violet-soft: #f1effd;
  --coral-soft: #fdefec;
  --amber-soft: #fdf4e4;
  --spectrum: linear-gradient(
    90deg, var(--teal), var(--sky) 28%, var(--violet) 52%, var(--coral) 76%,
    var(--amber)
  );

  --good: #2f7d55;
  --warn: #8a6a1d;
  --bad: #b23c26;

  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --body: "IBM Plex Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --shell: 1180px;
  --gutter: clamp(20px, 5vw, 56px);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

/* padding-inline, not the `padding` shorthand: `section` sets the vertical
   rhythm, and a shorthand here would silently reset it to zero on any
   <section class="shell"> — which is most of the site. */
.shell { max-width: var(--shell); margin: 0 auto; padding-inline: var(--gutter); }

/* --- type ---------------------------------------------------------------- */

h1, h2, h3 {
  color: var(--ink);
  font-family: var(--display);
  font-weight: 500;
  font-variation-settings: "SOFT" 0, "WONK" 0;
  letter-spacing: -0.015em;
  line-height: 1.06;
  text-wrap: balance;
  margin: 0;
}

h1 { font-size: clamp(2.5rem, 5vw, 3.9rem); }
/* Headings are 500, so a <strong> run inside one needs its own weight to
   read as emphasis. 600, not 700: 600 is the heaviest Fraunces this site
   serves (see scripts/fetch_fonts.py), and asking for a weight that is not
   there gets a browser-synthesised smear rather than the real cut. */
h1 strong, h2 strong { font-weight: 600; }
h2 { font-size: clamp(1.9rem, 3.4vw, 2.9rem); }
h3 { font-size: 1.22rem; line-height: 1.25; }

p { margin: 0 0 1em; max-width: 62ch; }

.lede { font-size: clamp(1.05rem, 1.6vw, 1.25rem); color: var(--mist); max-width: 56ch; }

/* The eyebrow is the spec-sheet tell: mono, small, wide, and it always names
   the section rather than decorating it. */
.eyebrow {
  font-family: var(--mono);
  font-size: 0.688rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.1rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}
.eyebrow.plain::after { display: none; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--mist); }

/* --- chrome -------------------------------------------------------------- */

header.top {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.90);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.top .bar {
  display: flex;
  align-items: center;
  gap: 2rem;
  height: 66px;
}
.brand {
  font-family: var(--display);
  font-size: 1.32rem;
  letter-spacing: -0.02em;
  text-decoration: none;
  white-space: nowrap;
}
.brand b { font-weight: 600; }
.brand span { color: var(--mist); font-weight: 400; }
.top nav { display: flex; gap: 1.6rem; margin-left: auto; align-items: center; }
/* Wide mono caps: the single strongest carrier of the machine-shop character.
   One rule to revert if it ever reads as too much. */
.top nav a {
  text-decoration: none;
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink);
  transition: color 0.15s;
}
.top nav a:hover, .top nav a[aria-current] { color: var(--accent); }
/* `.top nav a` is more specific than `.btn`, so without this the Buy button in
   the header takes the nav's link colour instead of its own on-accent white. */
.top nav a.btn { color: var(--paper); }
.top nav a.btn.ghost { color: var(--ink); }

footer.foot {
  border-top: 1px solid var(--line);
  margin-top: 6rem;
  /* ...except after the closing band, which already ends the page; the gap
     would read as the footer having come detached. */
  padding: 2.5rem 0 4rem;
  color: var(--faint);
  font-size: 0.875rem;
}
footer.foot .row { display: flex; gap: 2rem; flex-wrap: wrap; align-items: baseline; }
footer.foot a { color: var(--mist); text-decoration: none; }
footer.foot a:hover { color: var(--ink); }
main:has(.closing) + footer.foot { margin-top: 0; }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.82rem 1.5rem;
  border-radius: 3px;
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--paper);
  font: 600 0.95rem/1 var(--body);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn:hover { background: var(--accent-deep); }
.btn.ghost {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn.ghost:hover { border-color: var(--ink); background: var(--surface); }
.btn.small { padding: 0.55rem 1rem; font-size: 0.86rem; }
.btn[disabled] { opacity: 0.45; pointer-events: none; }

/* --- hero -----------------------------------------------------------------
   A photograph of the machine cutting, bleeding the full width, with the copy
   set on a deep-blue scrim over its left half. The photograph is warm and the
   palette is cool, so a blue veil sits over it — without that the hero belongs
   to a different site from everything below it. */

/* `section` sets the site's vertical rhythm; the hero opts out of it, or the
   photograph sits in a flat navy letterbox instead of filling the band. */
.hero { background: var(--deep); padding: 0; }
.hero .frame {
  position: relative;
  min-height: clamp(520px, 62vh, 660px);
  display: flex;
  align-items: center;
  overflow: hidden;
}
.hero .photo {
  position: absolute;
  inset: 0;
  background: url("/static/img/hero-machine.jpg") no-repeat 64% 58% / cover;
}
.hero .grade {
  position: absolute;
  inset: 0;
  background:
    /* the scrim the headline sits on */
    linear-gradient(97deg, var(--deep) 3%, rgba(7, 31, 52, 0.94) 26%,
      rgba(7, 31, 52, 0.62) 46%, rgba(7, 31, 52, 0.10) 70%),
    /* seams into the header above and the strip below */
    linear-gradient(180deg, rgba(7, 31, 52, 0.55), rgba(7, 31, 52, 0) 26%,
      rgba(7, 31, 52, 0) 62%, rgba(7, 31, 52, 0.75) 100%),
    /* the veil that marries a warm photograph to a cool palette */
    linear-gradient(rgba(13, 58, 102, 0.40), rgba(13, 58, 102, 0.40));
}
.hero .copy { position: relative; z-index: 2; width: 100%; padding-block: 3rem; }
.hero .copy > * { max-width: 34rem; }
.hero h1 { margin-bottom: 1.4rem; }
/* Three sentences, three lines. Left to wrap on its own it broke after
   "Preview", starting a line with "it." — which reads as a typo. */
h1.triple span { display: block; }

/* The same device where the break is the point rather than a rescue: the
   product on its own line, what it costs under it. */
h1.stacked span { display: block; }
h1.triple { line-height: 1.02; }
.hero .cta { display: flex; gap: 0.9rem; flex-wrap: wrap; margin-top: 2rem; }
.hero .note { margin-top: 1.4rem; font-size: 0.85rem; }
.hero-strip {
  margin-top: 0;
  border-top: 1px solid var(--line-dark);
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.hero-strip div {
  padding: 1.5rem 1.2rem 1.9rem;
  border-right: 1px solid var(--line-dark);
}
.hero-strip div:last-child { border-right: 0; }
.hero-strip dt {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}
.hero-strip dd { margin: 0; font-size: 0.95rem; }

/* The workspace screenshot, now leading the section that talks about it. */
.wide-shot {
  margin: 2.6rem 0 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: 0 20px 44px rgba(12, 47, 76, 0.10);
}
.wide-shot img { display: block; width: 100%; height: auto; }
.wide-shot figcaption {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  padding: 0.7rem 0.9rem;
  border-top: 1px solid var(--line);
}

/* --- the dark bands -------------------------------------------------------
   The hero and the closing call are the only dark surfaces on the site, and
   they bookend everything else. Each rule below exists because a light-ground
   colour is unreadable here: the tokens are global, so the flip is scoped
   rather than themed. */

.hero, .closing { color: var(--on-deep); border: 0; }
.hero h1, .closing h2 { color: #ffffff; }
.hero .lede, .closing .lede { color: var(--on-deep-mute); }
.hero .eyebrow, .closing .eyebrow { color: var(--accent-lift); }
.hero .eyebrow::after, .closing .eyebrow::after { background: var(--line-dark); }
.hero .note, .closing .note { color: var(--on-deep-faint); }
.hero .btn.ghost, .closing .btn.ghost {
  color: #ffffff;
  border-color: rgba(255, 255, 255, 0.42);
  background: rgba(7, 31, 52, 0.35);
}
.hero .btn.ghost:hover, .closing .btn.ghost:hover {
  border-color: #ffffff;
  background: rgba(255, 255, 255, 0.12);
}
.hero-strip dt { color: var(--on-deep-faint); }
.hero-strip dd { color: var(--on-deep-mute); }

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

section { padding: clamp(4rem, 9vw, 7rem) 0; }
/* The whole site is light, so a "paper" band is a change of shade rather than
   of polarity: warm ground, white cards sitting on it. */
section.paper { background: var(--ground-2); }

.cards {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.5rem;
}
@media (min-width: 720px) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1020px) { .cards.three { grid-template-columns: repeat(3, 1fr); } }
.card { background: var(--surface); padding: 1.9rem 1.7rem 2.1rem; }
.card h3 { margin-bottom: 0.6rem; }
.card p { color: var(--mist); font-size: 0.945rem; margin: 0; }
/* A card that is itself a link: same box, plus an affordance at the bottom. */
.card.link { text-decoration: none; display: flex; flex-direction: column;
  transition: background 0.15s; }
.card.link:hover { background: #fafcfd; }
.card.link .more { font-size: 0.85rem; font-weight: 600; color: var(--accent);
  margin-top: 1.1rem; }
.card.link:hover .more { text-decoration: underline; }
.card .n {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--accent);
  letter-spacing: 0.12em;
  display: block;
  margin-bottom: 1rem;
}

/* --- the three stages ------------------------------------------------------
   Design it / Preview it / Manufacture it — the words the application itself
   is organised around, so the site and the software teach the same vocabulary.
   Three equal columns on desktop, stacked below; the lists are the substance,
   so they get the room and the headings stay small. */

.steps {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.8rem;
}
@media (min-width: 900px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.step { background: var(--surface); padding: 2rem 1.8rem 2.2rem; }
.step .n {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--accent);
  display: block;
  margin-bottom: 0.9rem;
}
.step h3 { margin: 0 0 1.2rem; font-size: 1.32rem; }

.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li {
  position: relative;
  padding: 0 0 0 1.5rem;
  margin-bottom: 0.85rem;
  font-size: 0.945rem;
  line-height: 1.55;
  color: var(--mist);
}
.ticks li:last-child { margin-bottom: 0; }
.ticks li b { color: var(--ink); font-weight: 600; }
/* A drawn tick rather than a character: it stays put next to a wrapping line,
   and it takes the accent without dragging a font along for one glyph. */
.ticks li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.5rem;
  width: 5px;
  height: 9px;
  border-right: 1.6px solid var(--accent);
  border-bottom: 1.6px solid var(--accent);
  transform: rotate(42deg);
}

/* --- computed figures ----------------------------------------------------
   The toolpath plates are generated by scripts/site_figures.py from the real
   app.cam strategies, so they are drawings of what the software actually
   produces rather than illustrations of it. They are inked for a paper band. */

.plates {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.5rem;
}
@media (min-width: 780px) { .plates { grid-template-columns: repeat(2, 1fr); } }
.plate { background: #fff; padding: 1.4rem 1.4rem 1.1rem; }
.plate img { display: block; width: 100%; height: auto; }
.plate figcaption {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #6d757c;
  border-top: 1px solid var(--line);
  padding-top: 0.8rem;
  margin-top: 0.9rem;
}
.plate figcaption b { color: var(--ink); font-weight: 600; }
.plate-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--mist);
  margin: 1.1rem 0 0;
  display: flex;
  gap: 0.5rem 1.6rem;
  flex-wrap: wrap;
  /* It is a <p>, so the global 62ch measure applied and squeezed a four-item
     legend onto three lines. A key is a row, not running text. */
  max-width: none;
}
.plate-note span { display: inline-flex; align-items: center; gap: 0.5rem; }
.plate-note i { width: 22px; height: 0; border-top: 2px solid currentColor; }
.plate-note .k-cut { color: var(--accent); }
.plate-note .k-lift { color: #7fb4ec; }
.plate-note .k-lift i { border-top-width: 4px; }
.plate-note .k-rapid i { border-top-style: dashed; border-width: 1px; }

/* --- the feeds band ------------------------------------------------------
   Two panels side by side: the same operation posted with the option off and
   with it on, so the difference is three characters on one line rather than a
   paragraph of claims. The G-code is set in the mono face at a size that keeps
   an F word legible on a phone, where the panels stack. */

.feeds-split {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.5rem;
}
@media (min-width: 820px) { .feeds-split { grid-template-columns: 1fr 1fr; } }
.feeds-split > div { background: var(--surface); padding: 1.5rem 1.5rem 1.3rem; }
.feeds-split h3 {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mist);
  margin: 0 0 1rem;
  font-weight: 600;
}
.feeds-split h3 b { color: var(--ink); font-weight: 600; }
.gcode {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.82rem;
  line-height: 1.85;
  color: var(--text);
  margin: 0;
  overflow-x: auto;
}
.gcode b { color: var(--accent); font-weight: 600; }
.gcode i { color: var(--faint); font-style: normal; }
.feeds-split p.after {
  margin: 1.1rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  font-size: 0.9rem;
  color: var(--mist);
  max-width: none;
}

/* --- closing band --------------------------------------------------------
   The page used to end on a spec list and drop straight into the footer,
   which reads as a document running out rather than an argument finishing. */

.closing {
  border-top: 1px solid var(--line);
  background:
    radial-gradient(70% 150% at 50% 108%, rgba(26, 122, 224, 0.40), transparent 62%),
    linear-gradient(180deg, #0b3152, var(--deep));
  text-align: center;
}
.closing h2 { margin-bottom: 1rem; }
.closing .lede { margin-inline: auto; }
.closing .cta {
  display: flex;
  gap: 0.9rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 2.2rem;
}
.closing .note { margin: 1.6rem 0 0; font-size: 0.85rem; color: var(--faint); }

/* --- spec rows ----------------------------------------------------------- */

.specs { border-top: 1px solid var(--line); margin-top: 2rem; }
/* Two real columns, not a flex row with a minimum.
   `display: flex` with `min-width` on the name only sets a FLOOR: a name wider
   than it pushes the description across, so every row's prose started at a
   different place and the second column came out ragged. It showed on the
   workspace table, whose names are sentences rather than nouns -- seven of its
   nine are wider than the 230px floor and five are wider than 300px, against a
   longest toolpath name of 170px, which is why the toolpath tables below it
   looked fine.
   A grid track is a CEILING as well: the description column has one left edge
   whatever the name does, and a name too long for its column wraps inside it,
   which is what a two-column table is supposed to do. */
.specs div {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.3rem 1.5rem;
  align-items: baseline;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
}
/* Stacked until there is room for two columns: a 190px name beside prose on a
   phone leaves the prose about twenty characters wide. */
@media (min-width: 720px) {
  .specs div { grid-template-columns: 190px minmax(0, 1fr); }
}
/* The name column is what the page is SCANNED by -- someone checking whether
   the strategy they need is in the list reads only this column. It was set in
   --faint, which made the one thing being looked for the palest thing on the
   page. Accent blue at 600 gives the reference tables their only colour and
   turns the column into the index it already was. */
.specs dt {
  font-family: var(--mono);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-deep);
  /* A name that needs two lines gets two even ones rather than a single
     orphaned word under a full line. */
  text-wrap: balance;
}
.specs dd { margin: 0; }
.specs div:hover { background: rgba(26, 122, 224, 0.045); }

/* --- reference + guides --------------------------------------------------
   The informative pages: long tables of what the product is, and long-form
   writing about the work. Both are read rather than skimmed, so the measure is
   narrower and the vertical rhythm is looser than the marketing sections. */

.shell.narrow { max-width: 760px; }

/* A spec list used as a real reference table. The name column is wide enough
   that every strategy name -- the longest is 170px -- stays on one line, which
   is what makes the column scannable; the workspace table's sentence-length
   names wrap into it instead of stealing the prose column's width. */
@media (min-width: 720px) {
  .specs.wide div { grid-template-columns: 260px minmax(0, 1fr); }
}
/* Reference prose is the point of these pages, so it is set in the body ink,
   not the secondary grey a caption would take. */
.specs.wide dd { color: var(--text); }
.specs.wide + h2 { margin-top: 3.4rem; }
section h2 + .lede { margin-top: 0.7rem; }

.hero-strip.light { border-top-color: var(--line); }
.hero-strip.light div { border-right-color: var(--line); }
/* Same treatment as the spec tables: on a light ground the label naming each
   figure is accent blue, and the figure itself is body ink. Grey-on-grey read
   as a footnote rather than as the summary of the page it heads. */
.hero-strip.light dt { color: var(--accent-deep); font-weight: 600; }
.hero-strip.light dd { color: var(--text); }

.guides {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.8rem;
}
@media (min-width: 800px) { .guides { grid-template-columns: repeat(2, 1fr); } }
.guide {
  background: var(--surface);
  padding: 1.9rem 1.8rem 1.7rem;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  transition: background 0.15s;
}
.guide:hover { background: #fafcfd; }
.guide .n {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--faint);
}
.guide h3 { margin: 0; }
.guide p { color: var(--mist); font-size: 0.945rem; margin: 0; flex: 1; }
.guide .more {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  margin-top: 0.4rem;
}
.guide:hover .more { text-decoration: underline; }

.byline {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 1.6rem 0 0;
  padding-bottom: 1.6rem;
  border-bottom: 1px solid var(--line);
}
.prose { font-size: 1.06rem; line-height: 1.68; }
.prose p { margin: 0 0 1.15em; max-width: none; }
.prose h2 { font-size: 1.6rem; margin: 2.4rem 0 0.9rem; }
.prose .notice { margin: 2rem 0 1.2rem; font-size: 0.95rem; }
.bullets { margin: 0 0 1.3em; padding-left: 1.2rem; }
.bullets li { margin-bottom: 0.55em; }
.next { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--line); }

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

.price-wrap { display: grid; gap: 2.5rem; align-items: start; margin-top: 3rem; }
@media (min-width: 900px) { .price-wrap { grid-template-columns: 400px 1fr; } }
.price-card {
  border: 1px solid var(--line-strong);
  padding: 2.2rem 2rem 2.4rem;
  background: linear-gradient(180deg, var(--surface), var(--ground));
}
.price-card .amount {
  font-family: var(--display);
  font-size: 4rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
}
.price-card .amount sup {
  font-size: 1.35rem;
  font-family: var(--mono);
  color: var(--mist);
  top: -1.4em;
}
.price-card .once {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: 0.9rem;
}
.includes { list-style: none; padding: 0; margin: 1.8rem 0 0; }
.includes li {
  padding: 0.55rem 0 0.55rem 1.6rem;
  position: relative;
  font-size: 0.95rem;
  color: var(--mist);
  border-bottom: 1px solid var(--line);
}
.includes li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.95rem;
  width: 6px;
  height: 11px;
  border-right: 1.6px solid var(--accent);
  border-bottom: 1.6px solid var(--accent);
  transform: rotate(42deg);
}
.faq h3 { margin-top: 2rem; margin-bottom: 0.5rem; font-size: 1.05rem; }
.faq p { color: var(--mist); font-size: 0.95rem; }

/* --- forms + panels ------------------------------------------------------ */

.panel {
  border: 1px solid var(--line);
  background: var(--surface);
  padding: 1.8rem;
}
.panel + .panel { margin-top: 1.2rem; }
.panel h3 { margin-bottom: 1.1rem; }

form.stack { display: grid; gap: 1rem; max-width: 420px; }
label { display: block; font-size: 0.8rem; color: var(--mist); margin-bottom: 0.4rem; }
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"], input:not([type]),
select, textarea {
  width: 100%;
  padding: 0.72rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  color: var(--text);
  font: 400 0.95rem/1.3 var(--body);
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent-line);
  outline-offset: 1px;
}
textarea { resize: vertical; min-height: 4.5rem; }
/* A tick sits beside its words, not above them: the stacked-label rule above
   is for boxes you type into. */
label.check {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--text);
  font-size: 0.92rem;
}
label.check input { width: auto; }

/* The invoice is a document, not a page of the site: it needs to survive
   Ctrl-P, which is the only "download as PDF" it will ever have. */
.invoice .panel { max-width: 46rem; }

/* A general one-line group. ``footer.foot .row`` is older and more specific,
   so the footer keeps its own spacing. */
.row { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
.row > label { margin-bottom: 0; }
.toolbar { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; }
.toolbar .spacer { margin-left: auto; }
@media print {
  header.top, footer.foot, .no-print { display: none !important; }
  body { background: #fff; }
  .invoice .panel { border: 0; padding: 0; max-width: none; }
  main { padding: 0; }
  a[href]::after { content: ""; }
}

.keyline {
  font-family: var(--mono);
  font-size: 1.05rem;
  letter-spacing: 0.1em;
  padding: 0.9rem 1rem;
  background: var(--ground);
  border: 1px dashed var(--line-strong);
  word-break: break-all;
}

/* The way out of every admin page. Above the eyebrow rather than beside the
   heading: after a POST-redirect the browser's own Back button lands somewhere
   nobody asked for, so this has to be the obvious one, and obvious means first.  */
.admin-back { margin: 0 0 1.2rem; }

/* --- admin dashboard stats -------------------------------------------------
   Numbers first, label above, context below in small type. Same hairline grid
   as everything else so the admin area belongs to the same site rather than
   looking like the back office of another one. */
.stats {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.4rem;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 780px) { .stats { grid-template-columns: repeat(3, 1fr); } }
.stat { background: var(--surface); padding: 1.3rem 1.4rem 1.4rem; }
.stat-label {
  display: block;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mist);
}
.stat-value {
  display: block;
  margin-top: 0.5rem;
  font-size: 1.6rem;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-note {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.82rem;
  color: var(--faint);
}

/* --- the workspace band ----------------------------------------------------
   Eight capabilities, each a short title and a paragraph. Two columns at most:
   the paragraphs run to forty words and a third column would set them at a
   measure nobody reads. Same hairline grid as the steps and the plates, so the
   page has one way of showing a set of things rather than three. */
.traits {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.8rem;
}
@media (min-width: 820px) { .traits { grid-template-columns: repeat(2, 1fr); } }
.trait { background: var(--surface); padding: 1.9rem 1.8rem 2rem; }
.trait h3 {
  margin: 0 0 0.7rem;
  font-size: 1.14rem;
  line-height: 1.3;
  text-wrap: balance;
}
.trait p { margin: 0; font-size: 0.945rem; line-height: 1.6; }

/* A licence key exists to be pasted into the application, so it travels with
   the button that does it. The key keeps the width; the button sits beside it
   and drops beneath on a narrow screen. On paper it is not a button at all. */
.keyrow { display: flex; flex-wrap: wrap; align-items: stretch; gap: 0.6rem; }
.keyrow .keyline { flex: 1 1 16rem; }
.keyrow .btn.copy { flex: 0 0 auto; }
.btn.copy.done { border-color: var(--good); color: var(--good); }
@media print { .keyrow .btn.copy { display: none; } }

/* The way out of a password field: hint-sized, because it sits where the
   "at least 8 characters" note sits on the other form. */
.fieldlink { font-size: 0.78rem; }

.pill {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.28rem 0.6rem;
  border-radius: 2px;
  border: 1px solid currentColor;
}
.pill.ok { color: var(--good); }
.pill.warn { color: var(--warn); }
.pill.bad { color: var(--bad); }
.pill.muted { color: var(--faint); }

.notice {
  border-left: 2px solid var(--accent);
  background: var(--accent-soft);
  padding: 0.9rem 1.1rem;
  font-size: 0.92rem;
  margin-bottom: 1.4rem;
}
.notice.bad { border-color: var(--bad); background: rgba(209, 86, 63, 0.12); }
/* An action that worked, and one that is asking before it does something it
   cannot undo. Both carry their own words -- the colour is the second signal,
   never the only one. */
.notice.good { border-color: var(--good); background: rgba(47, 125, 85, 0.10); }
.notice.warn { border-color: var(--warn); background: rgba(138, 106, 29, 0.12); }

table.grid { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
table.grid th, table.grid td {
  text-align: left;
  padding: 0.75rem 0.9rem;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
table.grid th {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 400;
}
table.grid td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* The plan comparison. Built from a table of data (pages.PLANS), so a third
   column -- Ultra, when it ships -- costs one entry there and nothing here:
   the column widths come from the grid, not from a hand-tuned width per plan. */
table.plans { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
table.plans th[scope="col"] {
  text-align: center;
  padding: 0.9rem 0.8rem 1.1rem;
  border-bottom: 2px solid var(--line);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
}
table.plans th[scope="col"]:first-child { border-bottom-color: transparent; }
table.plans .plan-price {
  display: block;
  font-family: var(--mono);
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
  margin-top: 0.35rem;
}
table.plans .plan-note {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  margin-top: 0.2rem;
}
table.plans th[scope="row"] {
  text-align: left;
  font-weight: 400;
  padding: 0.7rem 0.9rem 0.7rem 0;
}
table.plans td {
  text-align: center;
  padding: 0.7rem 0.8rem;
  vertical-align: middle;
}
table.plans th[scope="row"], table.plans td {
  border-bottom: 1px solid var(--line);
}
table.plans td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* The one row that differs carries the weight; the dash is a fact, not a
   scolding, so it stays quiet rather than turning red. */
table.plans td.yes { color: var(--accent); font-size: 1.05rem; }
table.plans td.no { color: var(--faint); }
table.plans tr:last-child th, table.plans tr:last-child td { border-bottom: none; }

.dl-row {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.dl-row .what { flex: 1; min-width: 220px; }
.dl-row .what b { font-weight: 600; }
.dl-row .what span { display: block; color: var(--faint); font-size: 0.82rem; }

@media (prefers-reduced-motion: no-preference) {
  .rise { animation: rise 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  .rise:nth-child(2) { animation-delay: 0.06s; }
  @keyframes rise {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
  }
}

/* --- the gallery ----------------------------------------------------------
   Parts, not screens. One column on a phone, two above 780px: these are
   photographs of physical objects and halving them again makes them
   ornamental. A card is a figure — the image, then who it is and what made
   it — and the caption always says whether you are looking at a photograph or
   at a computed toolpath, because the page is worthless the moment those two
   become interchangeable. */
.pieces {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.8rem;
}
@media (min-width: 780px) { .pieces { grid-template-columns: repeat(2, 1fr); } }
.piece { background: var(--surface); margin: 0; display: flex; flex-direction: column; }
.piece img { display: block; width: 100%; height: auto; }
.piece img.plate-img { background: #fff; padding: 1.2rem 1.2rem 0; }
.piece .noshot {
  aspect-ratio: 3 / 2;
  display: grid;
  place-items: center;
  background: var(--ground-2);
  color: var(--faint);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.piece figcaption.shot {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 0.9rem 1.8rem 0;
}
.piece figcaption.shot.pending { color: var(--faint); }
.piece-copy { padding: 0.9rem 1.8rem 1.9rem; }
.piece-copy .n {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mist);
  display: block;
}
.piece-copy h3 { margin: 0.5rem 0 0.8rem; font-size: 1.28rem; }
.piece-copy p { margin: 0 0 0.9rem; }
.made-with { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0; }
.made-with span {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  border: 1px solid var(--line-strong);
  padding: 0.28rem 0.55rem;
}

/* --- quick start ----------------------------------------------------------
   The same numbered steps the home page uses, but ten of them and read in
   order, so they run two-up rather than three and the numbers stay legible. */
@media (min-width: 900px) {
  .steps.start { grid-template-columns: repeat(2, 1fr); }
}
.steps.start .step h3 { margin-bottom: 0.7rem; }
.steps.start .step p { margin: 0; }

/* --- searching the guides ------------------------------------------------- */
.find { margin-top: 2.4rem; max-width: 520px; }
.find-row { display: flex; gap: 0.6rem; }
.find-row input { flex: 1 1 auto; }
.find-row .btn { flex: 0 0 auto; }

/* A licence file, shown for copying. Monospace because the customer is going
   to eyeball it against what they pasted, and a proportional font turns
   "l1I" and "O0" into a support call. Small, because it is 400 characters of
   base64 and pretending otherwise wastes the screen. */
textarea.licence {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.5;
  letter-spacing: 0.01em;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}
ol.howto { margin: 0; padding-left: 1.3rem; }
ol.howto li { margin: 0.45rem 0; }

/* The other way in, under a sign-in or sign-up form. Separated by a rule with
   the word "or" sitting in it, because the two are alternatives rather than a
   sequence -- a plain gap reads as "and then". */
.altway {
  margin-top: 2rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
  position: relative;
}
.altway::before {
  content: "or";
  position: absolute;
  top: -0.62rem;
  left: 50%;
  transform: translateX(-50%);
  padding: 0 0.7rem;
  background: var(--ground);
  color: var(--mist);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.altway > span { font-size: 0.95rem; }
.altway .btn { margin-left: auto; }
.altway p.muted {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.82rem;
}
@media (max-width: 460px) {
  .altway .btn { margin-left: 0; width: 100%; text-align: center; }
}

/* --- the home page ---------------------------------------------------------
   The hero shows a part that came off the machine, framed on the deep band
   beside the headline. Below it: six capabilities, then one row per kind of
   work, each with a picture the application or its CAM engine produced. */

.hero.product .frame {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
  min-height: 0;
  padding-block: clamp(3rem, 7vw, 5.5rem);
  overflow: visible;
}
.hero.product .copy { padding-block: 0; }
@media (min-width: 960px) {
  .hero.product .frame { grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); }
}
.hero-shot { margin: 0; }
.hero-shot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: 4px;
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.35);
}
.hero-shot figcaption {
  margin-top: 0.8rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-deep-faint);
}

.features .shell { display: grid; gap: clamp(4rem, 8vw, 6.5rem); }
.feature { display: grid; gap: clamp(1.8rem, 4vw, 3.5rem); align-items: center; }
.feature .wide-shot { margin: 0; }
.feature h2 { font-size: clamp(1.6rem, 2.6vw, 2.2rem); margin-bottom: 0.9rem; }
.feature-copy > p { color: var(--mist); max-width: 52ch; margin: 0 0 1.4rem; }
.feature-more { margin: 1.6rem 0 0; font-weight: 600; font-size: 0.93rem; }
.feature-more a { color: var(--accent); text-decoration: none; }
.feature-more a::after { content: " \2192"; }
.feature-more a:hover { text-decoration: underline; }
@media (min-width: 900px) {
  .feature { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
  .feature.flip .wide-shot { order: 2; }
}

.ticks.also { margin-top: 2.2rem; display: grid; gap: 0.2rem 2.5rem; }
@media (min-width: 720px) { .ticks.also { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1020px) { .ticks.also { grid-template-columns: repeat(3, 1fr); } }
.ticks.also li { color: var(--ink); }

.guides + .cards { margin-top: 1.5rem; }

.buy-band { display: grid; gap: 2.5rem; align-items: center; }
@media (min-width: 900px) { .buy-band { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); } }
.buy-box {
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 2rem 1.9rem;
  display: grid;
  gap: 0.9rem;
  justify-items: start;
}
.buy-box .amount {
  font-family: var(--display);
  font-size: 3.4rem;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.buy-box .amount sup { font-size: 0.45em; vertical-align: 0.9em; margin-right: 0.1em; }
.buy-note { font-size: 0.8rem; color: var(--mist); margin: 0 0 0.4rem; }
.buy-box .btn { width: 100%; text-align: center; }

/* The toolpath board: every strategy the application generates, in the three
   groups the Toolpaths menu uses. Names carry the weight; the one-line
   purpose sits under each in the body grey. */
section.toolpaths { padding-top: 0; }
.tp-grid {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 2.5rem;
}
@media (min-width: 1020px) { .tp-grid { grid-template-columns: repeat(3, 1fr); } }
.tp-group { background: var(--surface); padding: 1.9rem 1.7rem 2rem; }
.tp-group h3 { margin: 0; }
.tp-sub {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0.35rem 0 1.4rem;
}
.tp-group dl { margin: 0; display: grid; gap: 1rem; }
.tp-group dt { font-weight: 600; color: var(--ink); font-size: 0.98rem; }
.tp-group dd { margin: 0.15rem 0 0; font-size: 0.88rem; line-height: 1.5; color: var(--mist); }
.feature-copy > .feature-more { margin: 1.6rem 0 0; }
/* An odd number of guides would leave a blank cell; the last one spans. */
.guides > .guide:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* Phones and small tablets: the header nav was wider than the screen and
   pushed the whole page sideways. It scrolls inside its own strip instead. */
@media (max-width: 940px) {
  .top .bar { gap: 1rem; }
  .top nav {
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    gap: 1.1rem;
    padding-block: 0.4rem;
  }
  .top nav::-webkit-scrollbar { display: none; }
  .top nav a { white-space: nowrap; flex: none; }
}
.closing .note { text-align: center; }

/* --- quick start: the three stages -----------------------------------------
   The strip mirrors the Stage selector in the application: three names, in
   order, left to right. Each chip jumps to its stage's steps. */
.stage-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.6rem;
  margin: 2.2rem 0 2rem;
}
.stage-chip {
  flex: 1 1 12rem;
  display: grid;
  gap: 0.2rem;
  padding: 1rem 1.1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.15s, background 0.15s;
}
.stage-chip:hover { border-color: var(--accent); background: var(--accent-soft); }
.stage-chip b { color: var(--ink); font-size: 1.15rem; font-family: var(--display); }
.stage-words > span:last-child { font-size: 0.88rem; color: var(--mist); }
.stage-n {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  color: var(--accent);
}
.stage-arrow {
  align-self: center;
  color: var(--accent);
  font-size: 1.3rem;
}
@media (max-width: 640px) { .stage-arrow { display: none; } }
.why-setup { margin: 0 0 2rem; }
.step.install { border: 1px solid var(--line); }
.stage-block:nth-of-type(odd) { background: var(--ground-2); }
.step .where {
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--accent-soft);
  border-radius: 4px;
  padding: 0.6rem 0.75rem;
  margin: 0 0 0.8rem;
}
.step .where span {
  display: block;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.2rem;
}
.steps.start .step p.where { margin-bottom: 0.8rem; }
@media (min-width: 900px) {
  .steps.start .step:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.stage-block { padding-top: clamp(3rem, 6vw, 4.5rem); }

/* --- a hidden licence key ---------------------------------------------------
   Dots until the eye is pressed. The eye is the label of a checkbox, so the
   toggle needs no script; the checkbox itself is kept in the tab order and
   visually hidden, and its focus ring is drawn on the eye. */
.keyfield { display: flex; align-items: center; gap: 0.6rem; position: relative; }
.keyfield .key-dots, .keyfield .key-plain { flex: 1 1 auto; min-width: 0; }
.keyfield .key-dots { letter-spacing: 0.18em; color: var(--mist); }
.keyfield .key-plain { display: none; }
.key-toggle {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.key-toggle:checked ~ .key-plain { display: inline; }
.key-toggle:checked ~ .key-dots { display: none; }
.key-eye {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  margin: -0.4rem -0.4rem -0.4rem 0;
  border-radius: 4px;
  color: var(--mist);
  cursor: pointer;
}
.key-eye:hover { color: var(--accent); background: var(--accent-soft); }
.key-toggle:focus-visible ~ .key-eye { outline: 2px solid var(--accent); outline-offset: 2px; }
.key-eye .eye-shut { display: none; }
.key-toggle:checked ~ .key-eye .eye-open { display: none; }
.key-toggle:checked ~ .key-eye .eye-shut { display: block; }
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
@media print {
  .keyfield .key-plain { display: inline; }
  .keyfield .key-dots, .key-eye { display: none; }
}

/* Paddle's figure is a whole formatted string ("US$599.00", "₹52,999.00"),
   longer than our own symbol-plus-number; it wraps rather than overflowing
   the card, and stays one size whatever the currency. */
.price-card .amount[data-paddle-total] {
  font-size: clamp(2.4rem, 9vw, 3.4rem);
  flex-wrap: wrap;
  overflow-wrap: anywhere;
  min-height: 1em;
}

/* --- account: profile panel ---------------------------------------------- */
#profile { margin-top: 2rem; }
#profile .notice { margin: 0 0 1rem; }
.profile-actions {
  display: grid;
  gap: 0.2rem;
  margin-top: 0.6rem;
}
.profile-actions details { border-bottom: 1px solid var(--line); }
.profile-actions summary {
  cursor: pointer;
  padding: 0.7rem 0;
  font-weight: 600;
  color: var(--accent);
  list-style-position: inside;
}
.profile-actions summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.profile-actions details[open] summary { color: var(--text); }
.profile-actions details form { margin: 0.4rem 0 1.2rem; }
.profile-action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  padding-top: 1rem;
}
.profile-action .muted { font-size: 0.85rem; }

/* The quick start, one line under the hero's buttons: the first thing a new
   operator wants after "download" is "and then what". */
.hero .hero-start { margin-top: 1.2rem; font-size: 0.95rem; }
.hero .hero-start a {
  color: var(--on-deep);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-underline-offset: 0.25em;
}
.hero .hero-start a:hover { color: var(--accent); }

/* Eight entries once Quick start joined the header. Signed in, "Account" and
   "Sign out" are wider than "Sign in" and "Buy", and between the phone
   breakpoint and a wide screen the labels broke onto two lines. They stay on
   one, and the spacing gives way first. */
.top nav a { white-space: nowrap; }
@media (min-width: 941px) and (max-width: 1180px) {
  .top nav { gap: 1rem; }
  .top nav a.btn { padding-inline: 0.8rem; }
}

/* --- the application's own icons ----------------------------------------- */
/* The same pictures as the buttons in the app (scripts/site_icons.py copies
   them), so the page and the screen look like the same thing. The tile is the
   rounded square the ribbon draws behind its large buttons. */
.app-icon { display: block; flex: none; }
.app-icon.blank { display: inline-block; }
.icon-tile.empty { border-color: transparent; background: transparent; }
.icon-tile {
  flex: none;
  display: inline-grid;
  place-items: center;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
}
.named { display: flex; align-items: center; gap: 0.75rem; }
h2.named, h3.named { text-wrap: balance; }

/* Quick start: the stage chips carry the Stage selector's icons. */
.stage-chip {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.stage-chip .icon-tile { padding: 7px; border-radius: 10px; }
.stage-words { display: grid; gap: 0.2rem; }
.stage-block h2.named { gap: 1rem; }
.steps.start .step h3.named { gap: 0.7rem; }

/* Home page toolpath board: each strategy beside its button. */
.tp-row dt.named { gap: 0.8rem; }
.tp-row .icon-tile { padding: 4px; border-radius: 7px; }
/* The description lines up under the name, not under the icon. */
.tp-row dd { margin-left: calc(46px + 0.8rem); }
.specs dt .named { gap: 0.6rem; }

/* --- colour -------------------------------------------------------------- */
/* Each tone class sets --tone and --tone-soft; the components below read
   them. A thing with no tone falls back to the blue accent. */
.tone-setup, .tone-teal { --tone: var(--teal); --tone-soft: var(--teal-soft); }
.tone-design, .tone-violet { --tone: var(--violet); --tone-soft: var(--violet-soft); }
.tone-manufacture, .tone-coral { --tone: var(--coral); --tone-soft: var(--coral-soft); }
.tone-preview, .tone-amber { --tone: var(--amber); --tone-soft: var(--amber-soft); }
.tone-sky { --tone: var(--sky); --tone-soft: var(--sky-soft); }

/* The spectrum under the header, the one place every colour appears. */
header.top { border-bottom: 0; }
header.top::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: var(--spectrum);
}

/* Capability cards: a coloured top edge and eyebrow by stage. */
.card[class*="tone-"] { box-shadow: inset 0 3px 0 var(--tone); }
.card[class*="tone-"] .n { color: var(--tone); }

/* The toolpath board: each column in its family's colour, and the icon
   tiles tinted to match. */
.tp-group[class*="tone-"] { box-shadow: inset 0 3px 0 var(--tone); }
.tp-group[class*="tone-"] .tp-sub { color: var(--tone); }
.tp-group[class*="tone-"] .icon-tile:not(.empty) {
  background: var(--tone-soft);
  border-color: color-mix(in srgb, var(--tone) 22%, transparent);
}

/* Guides: the cards take the companions in turn. */
.guide { box-shadow: inset 3px 0 0 var(--tone, var(--accent)); }
.guide:nth-child(4n + 1) { --tone: var(--teal); }
.guide:nth-child(4n + 2) { --tone: var(--violet); }
.guide:nth-child(4n + 3) { --tone: var(--coral); }
.guide:nth-child(4n + 4) { --tone: var(--amber); }
.guide .more { color: var(--tone, var(--accent)); }

/* "In every job": the ticks take the companions in turn. */
.ticks.also li:nth-child(4n + 1)::before { border-color: var(--teal); }
.ticks.also li:nth-child(4n + 2)::before { border-color: var(--violet); }
.ticks.also li:nth-child(4n + 3)::before { border-color: var(--coral); }
.ticks.also li:nth-child(4n + 4)::before { border-color: var(--amber); }

/* The buy band on the home page: a warm tint, as smepoint's closing band. */
section.paper:has(.buy-band) {
  background: linear-gradient(180deg, var(--amber-soft), #fffaf2);
}

/* Quick start: each stage in its own colour, chip and band alike. */
.stage-chip[class*="tone-"] { box-shadow: inset 0 3px 0 var(--tone); }
.stage-chip[class*="tone-"] .stage-n { color: var(--tone); }
.stage-chip[class*="tone-"]:hover {
  border-color: var(--tone);
  background: var(--tone-soft);
}
.stage-chip[class*="tone-"] .icon-tile,
.stage-block[class*="tone-"] h2 .icon-tile {
  background: var(--tone-soft);
  border-color: color-mix(in srgb, var(--tone) 25%, transparent);
}
.stage-block[class*="tone-"] .eyebrow { color: var(--tone); }
.stage-block[class*="tone-"] .eyebrow::after { background: var(--tone); opacity: 0.35; }
.stage-block[class*="tone-"] .step .n { color: var(--tone); }
.stage-block.tone-setup { background: linear-gradient(180deg, var(--teal-soft), var(--ground) 18rem); }
.stage-block.tone-design { background: linear-gradient(180deg, var(--violet-soft), var(--ground) 18rem); }
.stage-block.tone-manufacture { background: linear-gradient(180deg, var(--coral-soft), var(--ground) 18rem); }

/* --- the user manual ------------------------------------------------------
   A reference, read in pieces: a contents column that stays put, a text
   column held to a reading measure, and the chapter's stage colour on the
   things that orient you (eyebrow, step numbers, the rule over each card).
   Settings are a definition list, because that is what they are: a name on
   screen and what it does. The same markup prints to the PDF. */

.m-top { padding-bottom: 2rem; }
.m-top .note { margin-top: 1.4rem; font-size: 0.92rem; color: var(--mist); max-width: 62ch; }
.m-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.8rem; }
.m-size { font-family: var(--mono); font-size: 0.72rem; opacity: 0.75; margin-left: 0.35rem; }

.m-index { padding-top: 0; }
.m-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.m-card {
  background: var(--surface);
  padding: 1.7rem 1.6rem 1.8rem;
  box-shadow: inset 0 3px 0 var(--tone, var(--accent));
}
.m-card-n {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--tone, var(--accent)); margin: 0 0 0.6rem;
}
.m-card h2 { font-size: 1.4rem; margin: 0 0 0.55rem; }
.m-card h2 a { text-decoration: none; }
.m-card h2 a:hover { color: var(--tone, var(--accent)); }
.m-card > p { color: var(--mist); font-size: 0.92rem; margin: 0 0 1rem; }
.m-card-sections { list-style: none; margin: 0; padding: 0; font-size: 0.86rem; columns: 2; column-gap: 1.2rem; }
.m-card-sections li { break-inside: avoid; margin-bottom: 0.3rem; }
.m-card-sections a { color: var(--text); text-decoration: none; }
.m-card-sections a:hover { color: var(--tone, var(--accent)); text-decoration: underline; }

section.m-page { padding-top: clamp(2.2rem, 5vw, 3.5rem); }
.m-wrap {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.m-nav {
  position: sticky;
  top: 88px;
  max-height: calc(100vh - 110px);
  overflow-y: auto;
  font-size: 0.88rem;
  padding-right: 0.4rem;
}
.m-nav-head { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; margin: 0 0 0.9rem; }
.m-nav-head a { text-decoration: none; color: var(--accent); }
.m-nav ol { list-style: none; margin: 0; padding: 0; }
.m-nav-chapters > li { border-left: 2px solid var(--line); }
.m-nav-chapters > li.here { border-left-color: var(--tone); }
.m-nav-chapters > li > a {
  display: flex; gap: 0.6rem; padding: 0.42rem 0 0.42rem 0.8rem;
  text-decoration: none; color: var(--ink); line-height: 1.3;
}
.m-nav-chapters > li > a:hover { color: var(--tone); }
.m-nav-chapters > li.here > a { font-weight: 600; color: var(--tone); }
.m-num { font-family: var(--mono); font-size: 0.74rem; color: var(--faint); min-width: 1.1rem; padding-top: 0.1rem; }
.m-nav-sections { padding: 0 0 0.6rem 2.7rem !important; }
.m-nav-sections a { display: block; padding: 0.2rem 0; color: var(--mist); text-decoration: none; line-height: 1.3; }
.m-nav-sections a:hover { color: var(--ink); }
.m-nav-pdf { margin: 1.3rem 0 0; font-size: 0.84rem; }
.m-nav-pdf a { color: var(--accent); }

.m-body { max-width: 74ch; font-size: 1.02rem; line-height: 1.68; }
.m-body > .eyebrow { color: var(--tone, var(--accent)); }
.m-body > .eyebrow a { color: inherit; text-decoration: none; }
.m-body > h1 { font-size: clamp(2.2rem, 4.4vw, 3.2rem); text-wrap: balance; }
.m-body > .lede { margin: 0.9rem 0 2.4rem; }
section.m-section { padding: 0; margin: 0 0 2.6rem; scroll-margin-top: 90px; }
.m-section h2 { font-size: clamp(1.45rem, 2.4vw, 1.8rem); margin: 0 0 0.9rem; padding-top: 1.6rem;
  border-top: 1px solid var(--line); text-wrap: balance; }
.m-section h2 .m-anchor { text-decoration: none; color: inherit; }
.m-section h2 .m-anchor:hover::after { content: " #"; color: var(--faint); }
.m-section h3 { font-size: 1.08rem; margin: 1.6rem 0 0.6rem; }
.m-section p { margin: 0 0 1em; }
.m-section b { color: var(--ink); font-weight: 600; }
.m-section code, .m-body code {
  font-family: var(--mono); font-size: 0.86em; background: var(--ground-2);
  border: 1px solid var(--line); border-radius: 3px; padding: 0.05em 0.35em;
  overflow-wrap: anywhere;
}
.m-steps { counter-reset: step; list-style: none; padding: 0; margin: 0 0 1.3em; }
.m-steps li { counter-increment: step; position: relative; padding-left: 2.4rem; margin-bottom: 0.6em; }
.m-steps li::before {
  content: counter(step);
  position: absolute; left: 0; top: 0.15em;
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--tone-soft, var(--accent-soft)); color: var(--tone, var(--accent));
  font-family: var(--mono); font-size: 0.78rem; font-weight: 600;
  display: grid; place-items: center;
}
.m-fields { margin: 0 0 1.4em; border-top: 1px solid var(--line); }
.m-row { display: grid; grid-template-columns: minmax(9rem, 13rem) 1fr; }
.m-fields dt, .m-fields dd { margin: 0; padding: 0.6rem 0; border-bottom: 1px solid var(--line); }
.m-fields dt { font-weight: 600; color: var(--ink); padding-right: 1.2rem; font-size: 0.95rem; }
.m-fields dd { color: var(--text); }

.m-pager {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 3.5rem;
  background: var(--line); border: 1px solid var(--line);
}
.m-pager a, .m-pager > span { background: var(--surface); padding: 1.1rem 1.3rem; text-decoration: none; color: var(--ink); font-weight: 600; }
.m-pager a span { display: block; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint); font-weight: 400; margin-bottom: 0.25rem; }
.m-pager a:hover { background: var(--ground-2); }
.m-pager .next { text-align: right; }

.m-cover { padding: 1rem 0 2.5rem; border-bottom: 1px solid var(--line); margin-bottom: 2.5rem; }
.m-cover h1 { font-size: clamp(2.8rem, 6vw, 4.4rem); }
.m-cover-foot { font-family: var(--mono); font-size: 0.75rem; color: var(--faint); margin-top: 2rem; }
.m-contents h2 { font-size: 1.6rem; margin-bottom: 1rem; }
.m-contents > ol { list-style: none; padding: 0; margin: 0 0 3rem; }
.m-contents > ol > li { margin-bottom: 0.9rem; }
.m-contents > ol > li > a { display: flex; gap: 0.6rem; font-weight: 600; text-decoration: none; color: var(--ink); }
.m-contents > ol > li > a .m-num { color: var(--tone); }
.m-contents ol ol { list-style: none; padding: 0.2rem 0 0 1.7rem; margin: 0; columns: 2; column-gap: 1.5rem; font-size: 0.88rem; }
.m-contents ol ol a { color: var(--mist); text-decoration: none; }
.m-all .m-print-chapter { max-width: none; padding-top: 2.5rem; margin-top: 1rem; border-top: 3px solid var(--tone); }
.m-all .m-print-chapter > .eyebrow { margin-bottom: 0.6rem; }

@media (max-width: 900px) {
  .m-wrap { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
  .m-nav { position: static; max-height: none; overflow: visible; padding: 0 0 1.2rem;
    border-bottom: 1px solid var(--line); }
  .m-nav-sections { display: none; }
  .m-nav-chapters { columns: 2; column-gap: 1rem; }
  .m-nav-chapters > li { break-inside: avoid; }
}
@media (max-width: 560px) {
  .m-row { grid-template-columns: minmax(0, 1fr); }
  .m-fields dt { border-bottom: 0; padding-bottom: 0.1rem; }
  .m-fields dd { padding-top: 0; }
  .m-card-sections, .m-contents ol ol, .m-nav-chapters { columns: 1; }
  .m-pager { grid-template-columns: minmax(0, 1fr); }
  .m-pager .next { text-align: left; }
}

@media print {
  @page { size: A4; margin: 16mm 16mm 18mm; }
  header.top, footer.foot, .m-nav, .m-pager, .m-screen-only { display: none !important; }
  body { font-size: 10pt; line-height: 1.5; background: #fff; }
  section.m-page { padding: 0; }
  .shell { max-width: none; padding: 0; }
  .m-body { max-width: none; font-size: 10pt; }
  .m-cover { min-height: 240mm; display: flex; flex-direction: column; justify-content: center;
    border: 0; break-after: page; }
  .m-contents { break-after: page; }
  .m-all .m-print-chapter { break-before: page; border-top: 0; margin: 0; padding-top: 0; }
  .m-section h2 { break-after: avoid; padding-top: 0.8rem; }
  .m-section h3 { break-after: avoid; }
  /* Keep a heading with what follows it: a section's heading, its opening
     paragraph and the first rows of its list stay on one page, and the page
     breaks between rows rather than carrying a whole list over. */
  .m-row, .m-steps li, .bullets li { break-inside: avoid; }
  .m-section h2, .m-section h3 { break-after: avoid; break-inside: avoid; }
  .m-section h2 + p, .m-section h3 + p, .m-section h2 + dl, .m-section h3 + dl,
  .m-section p + dl, .m-section h2 + ol, .m-section p + ol { break-before: avoid; }
  .m-section p { orphans: 3; widows: 3; }
  .m-cover-logo { width: 80mm; height: auto; }
  .m-section h2 .m-anchor:hover::after { content: none; }
  a { color: inherit; text-decoration: none; }
}

/* Manual: the ribbon's own icons, beside the section a command gets and the
   settings-list terms that are commands. Smaller tiles than the Quick start's,
   because they sit inside running text. */
.m-section h2.named { gap: 0.8rem; }
.m-section h2 .m-icon { padding: 5px; border-radius: 8px; }
.m-fields dt.named { display: flex; align-items: flex-start; gap: 0.55rem; }
.m-fields dt .m-icon { padding: 3px; border-radius: 6px; margin-top: -0.05rem; }
@media (max-width: 560px) { .m-fields dt.named { border-bottom: 0; } }
@media print { .icon-tile { break-inside: avoid; } }

/* --- the Carvect logo ------------------------------------------------------
   The mark (emblem only) where the logo is small -- the header, the tab; the
   full logo where it can be read -- the closing band, the footer and the
   manual. The reversed logo is for the navy bands only. */
.brand { display: inline-flex; align-items: center; gap: 0.55rem; }
.brand-mark { width: auto; height: 34px; flex: none; }

/* Older builds a licence still covers: present, and quieter than the
   current one, because going back a version is the exception. */
.dl-older {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.55rem 0 0.9rem;
  font-size: 0.92rem;
  color: var(--mist);
}
.dl-older .mono { font-size: 0.72rem; letter-spacing: 0.08em; }
/* The full logo is never shown smaller than about 260px wide: below that the
   tagline under the wordmark stops being readable. */
.closing-logo { display: block; width: 320px; max-width: 80%; height: auto;
  margin: 0 auto 2.2rem; }
footer.foot .foot-logo { flex: none; align-self: center; }
footer.foot .foot-logo img { display: block; width: 280px; max-width: 100%; height: auto; }
footer.foot .foot-text { flex: 1 1 22rem; display: flex; flex-direction: column;
  gap: 0.9rem; align-self: center; line-height: 1.7; }
.m-top-grid { display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(1.5rem, 4vw, 4rem); align-items: center; }
.m-top-logo { width: clamp(260px, 26vw, 340px); height: auto; }
.m-cover-logo { display: block; width: 320px; height: auto; margin-bottom: 2rem; }
@media (max-width: 700px) {
  .m-top-grid { grid-template-columns: minmax(0, 1fr); }
  .m-top-logo { order: -1; width: 260px; }
}

/* --- support tickets ------------------------------------------------------
   A thread reads top to bottom, oldest first. Who wrote each message is the
   first thing on its line; support's messages carry a tinted rule so the two
   voices can be told apart at a glance, and an internal note (support's pages
   only) is amber so nobody mistakes it for something the customer saw. */
form.stack.wide { max-width: 760px; }
.thread { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.msg { border-left: 2px solid var(--line-strong); padding: 0.2rem 0 0.2rem 1rem; }
.msg.support { border-left-color: var(--accent); }
.msg.note { border-left-color: var(--amber); background: var(--amber-soft);
  padding: 0.7rem 1rem; }
.msg-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.6rem;
  font-size: 0.9rem; color: var(--ink); margin-bottom: 0.35rem; }
.msg-when { font-family: var(--mono); font-size: 0.72rem; color: var(--faint);
  margin-left: auto; }
.msg-body { font-size: 0.95rem; line-height: 1.6; overflow-wrap: anywhere; }
.msg.event { border-left-color: transparent; font-size: 0.85rem;
  color: var(--mist); display: flex; flex-wrap: wrap; gap: 0.6rem; }
.msg.event .msg-when { margin-left: 0; }
