/* ============================================================================
   FIGURE SHEET — the site's visual world. Scoped to .fs, which is on <body> of
   all nine pages. Loaded after styles.css.
   See DESIGN.md for the system this implements.
   ========================================================================== */

/* ── styles.css token remap ───────────────────────────────────────────────────
   styles.css still ships (create/dashboard lean on its component rules) and its
   :root tokens are the previous visual world: emerald accent, slate primary,
   8-18px radii, deep shadows. Because .fs is on <body>, redefining those tokens
   here re-points every old rule at this world instead of overriding them one
   property at a time — which is what let emerald, slate and 18px radii reach
   production on all nine pages after the migration.

   ponytail: token remap, not a rewrite. Delete this block if styles.css is ever
   retired; the literal-value resets below it go at the same time. */
.fs {
  --color-background: #fbfbfa;
  --color-surface: #fbfbfa;
  --color-surface-2: #f4f3f0;
  --color-foreground: #14130f;
  --color-muted: #57544c;
  --color-subtle: #57544c;
  --color-primary: #14130f;
  --color-secondary: #57544c;
  --color-accent: #1d4ed8;
  --color-accent-2: #16309b;
  --color-accent-soft: #e8eefc;
  --color-blue-soft: #e8eefc;
  --color-orange-soft: #e8eefc;
  --color-border: #e4e3df;
  --color-border-strong: #cbc9c2;
  --color-ring: #1d4ed8;
  --color-ink: #14130f;
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;
  --radius-sm: 2px;
  --radius-lg: 2px;
}

.fs {
  --sheet: #fbfbfa;
  --sheet-2: #f4f3f0;
  --rule: #e4e3df;
  --rule-strong: #cbc9c2;
  --ink: #14130f;
  --ink-muted: #57544c;
  --blueline: #1d4ed8;
  --blueline-deep: #16309b;
  --blueline-wash: #e8eefc;
  --neg: #14130f;
  --neg-line: #fbfbfa;
  --neg-muted: #a29e94;

  --letter: "Barlow Semi Condensed", "Helvetica Neue", Arial, sans-serif;
  --spec: "Barlow", "Helvetica Neue", Arial, sans-serif;

  /* ── Lettering ladder ───────────────────────────────────────────────────────
     A drafting standard does not have a continuous type scale; it has a fixed
     lettering ladder, and every note on the sheet is set at one of its heights.
     ISO 3098 runs 2.5 / 3.5 / 5 / 7 / 10 / 14 / 20 mm — fine steps where notes
     live, root-2 leaps for titles. This is that ladder in rem.

     Ten heights. Nothing on this site is set at a size that is not one of them.
     (It previously ran 35, twenty-two of which were within 6% of a neighbour —
     which is not a scale, it is rounding noise with a stylesheet around it.) */
  --t-micro:  0.64rem;                        /* 10.2px — stamps, badge text   */
  --t-letter: 0.72rem;                        /* 11.5px — title-block fields   */
  --t-callout:0.82rem;                        /* 13.1px — actions, numerals    */
  --t-small:  0.94rem;                        /* 15.0px — dense spec text      */
  --t-body:   1.0625rem;                      /* 17.0px — specification text   */
  --t-lead:   clamp(1.05rem, 1.5vw, 1.22rem); /* the abstract under a heading  */
  --t-h3:     clamp(1.15rem, 2vw, 1.5rem);
  --t-h2-sm:  clamp(1.5rem, 3vw, 2.3rem);     /* sheet sub-heading, plate caps */
  --t-h2:     clamp(1.9rem, 4.4vw, 3.3rem);
  --t-h1:     clamp(2.5rem, 6vw, 4.7rem);

  /* Tracking follows the size regime, the way it does on a real sheet: caps set
     large close up, caps set small open out so the strokes stay countable. */
  --tr-display: -0.02em;  /* headings at h2-sm and above                       */
  --tr-heading:  0.02em;  /* uppercase headings below display size             */
  --tr-callout:  0.08em;  /* actions and numerals — DESIGN.md's callout figure */
  --tr-letter:   0.14em;  /* the title-block alphabet — DESIGN.md's lettering  */

  /* Six faces load; author against these five names and nothing else. Barlow
     ships 400/500/700 and Semi Condensed 600/700/800 — any other number snaps
     silently to one of them, so a stylesheet that names 15 weights renders 6. */
  --w-spec:     400;
  --w-spec-med: 500;
  --w-letter:   600;
  --w-strong:   700;
  --w-display:  800;

  --lh-display: 0.94;   /* condensed caps, set tight — the sheet's title block */
  --lh-heading: 1.15;
  --lh-letter:  1.2;
  --lh-spec:    1.62;

  /* ── The division ladder ────────────────────────────────────────────────
     `.fs main` prints a 30px drafting grid. That grid is the module, so every
     division of the sheet is a whole number of it and the spacing system is
     literally drawn on the page. Six rungs, replacing fifty-one measured
     values — nine of which were near-identical clamps for the single role
     "space a sheet band" (2.4/5vw/4, 2.2/5vw/3.8, 2/5vw/3.4, 2.6/6vw/4.5,
     2.4/6vw/4, 1.8/4vw/2.8, 1.9/4vw/2.8, 2.2/5vw/3.6, 1.6/4vw/2.6) and ten
     more for "inset a card". Author against the rung, never a number.

     The bottom rung was a QUARTER module (7.5px) on the first pass and it was
     too tight: everything the old sheet spaced at 11-13px — two fields side by
     side, a label above its slider, the gap inside a chip — collapsed onto it,
     and controls that had read as groups mushed together. A third of the
     module is the honest bottom: 10 / 15 is a step a reader can see, and both
     are whole divisions of the printed grid. */
  --d1:   10px;   /* third of the module — inside a control, chip inset */
  --d2:   15px;   /* half     — label to field, row rhythm */
  --d3:   30px;   /* MODULE   — a card's inset, a tight gutter */
  --d4:   45px;   /* 1.5      — the division between cells of one field */
  --d5:   60px;   /* 2        — a band inside a sheet */
  --d6:   90px;   /* 3        — a sheet against its neighbour */

  --gut: clamp(15px, 4vw, 45px);
  --sheet-max: 1260px;
  --hair: 1px;
  --radius: 2px;
  --draw: cubic-bezier(0.16, 1, 0.3, 1);

  background: var(--sheet);
  color: var(--ink);
  font-family: var(--spec);
  font-size: 17px;
  -webkit-font-smoothing: antialiased;
}

/* Drafting paper: an 8mm grid, barely there, plus the sheet's own edge. */
.fs main {
  background-image:
    linear-gradient(to right, rgba(20, 19, 15, 0.045) var(--hair), transparent var(--hair)),
    linear-gradient(to bottom, rgba(20, 19, 15, 0.045) var(--hair), transparent var(--hair));
  background-size: 30px 30px;
  background-position: -1px -1px;
}

.fs ::selection { background: var(--blueline); color: var(--sheet); }
.fs :focus-visible { outline: 2px solid var(--blueline); outline-offset: 3px; }

/* ── Lettering primitives ─────────────────────────────────────────────────── */
.fs .letter,
.fs .fs-field-key,
.fs .fs-figno,
.fs .fs-sheetno,
.fs .fs-cap {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  text-transform: uppercase;
  letter-spacing: var(--tr-letter);
  font-size: var(--t-letter);
  line-height: var(--lh-heading);
}

.fs h1, .fs h2, .fs h3 {
  font-family: var(--letter);
  font-weight: var(--w-display);
  text-transform: uppercase;
  letter-spacing: var(--tr-display);
  line-height: var(--lh-display);
  text-wrap: balance;
  margin: 0;
}
.fs h1 { font-size: var(--t-h1); }
.fs h2 { font-size: var(--t-h2); }
.fs h3 { font-size: var(--t-h3); letter-spacing: var(--tr-heading); }

.fs p { margin: 0 0 var(--d2); line-height: var(--lh-spec); color: var(--ink-muted); max-width: 66ch; }
.fs p:last-child { margin-bottom: 0; }

/* A reference numeral in prose points at the same numeral in the drawing. */
.fs .ref {
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-callout);
  color: var(--blueline);
  letter-spacing: var(--tr-letter);
  white-space: nowrap;
}

/* ── Title block (site header) ────────────────────────────────────────────── */
.fs .site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: stretch;
  gap: 0;
  padding: 0;
  margin: 0;
  max-width: none;
  background: var(--sheet);
  border: none;
  border-bottom: var(--hair) solid var(--ink);
  box-shadow: none;
  backdrop-filter: none;
}

.fs .site-header > * { min-width: 0; }

.fs .brand {
  display: flex;
  align-items: center;
  gap: var(--d1);
  padding: 0 var(--d3);
  border-right: var(--hair) solid var(--ink);
  text-decoration: none;
}
.fs .brand-logo { height: 26px; width: auto; display: block; }
/* The mark ships in the old palette; the sheet has one hue and it is blueline. */
.fs .brand-logo { filter: grayscale(1) contrast(1.4); }

.fs .nav-links {
  display: flex;
  align-items: stretch;
  justify-content: flex-start;
  gap: 0;
  background: none;
  border: none;
  padding: 0;
}
.fs .nav-links a {
  display: flex;
  align-items: center;
  padding: var(--d2);
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
  text-decoration: none;
  border: none;
  border-right: var(--hair) solid var(--rule);
  border-radius: 0;
  background: none;
  transition: color 0.18s var(--draw), background 0.18s var(--draw);
}
.fs .nav-links a:first-child { border-left: var(--hair) solid var(--rule); }
@media (hover: hover) and (pointer: fine) {
  .fs .nav-links a:hover { color: var(--ink); background: var(--sheet-2); }
}
.fs .nav-links a.is-active {
  color: var(--blueline);
  background: var(--blueline-wash);
  box-shadow: inset 0 -3px 0 var(--blueline);
}

.fs .nav-auth,
.fs .nav-cta {
  display: flex;
  align-items: center;
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  border-radius: 0;
  border: none;
  border-left: var(--hair) solid var(--ink);
  padding: var(--d2);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.18s var(--draw), color 0.18s var(--draw);
}
.fs .nav-auth { background: none; color: var(--ink); }
.fs .nav-auth:hover { background: var(--sheet-2); }
.fs .nav-cta { background: var(--blueline); color: #fff; }
.fs .nav-cta:hover { background: var(--blueline-deep); }

.fs .nav-toggle {
  display: none;
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  background: none;
  border: none;
  border-left: var(--hair) solid var(--ink);
  border-radius: 0;
  padding: var(--d2);
  color: var(--ink);
  cursor: pointer;
}

/* ── Sheet shell ──────────────────────────────────────────────────────────── */
.fs .fs-sheet {
  position: relative;
  border-bottom: var(--hair) solid var(--ink);
}
.fs .fs-inner {
  width: min(var(--sheet-max), calc(100% - var(--gut) * 2));
  margin-inline: auto;
}

/* Every sheet carries its number and subject, drafting-style. */
.fs .fs-stamp {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--d2);
  flex-wrap: wrap;
  padding: var(--d1) 0;
  border-bottom: var(--hair) solid var(--rule);
  color: var(--ink-muted);
}
.fs .fs-stamp b { font-weight: var(--w-strong); color: var(--ink); }

/* ── SHEET 1 — title sheet ────────────────────────────────────────────────── */
.fs .fs-title-sheet { padding-bottom: var(--d5); }
.fs .fs-title-grid {
  display: grid;
  gap: var(--d5);
  align-items: center;
  padding-top: var(--d5);
}
@media (min-width: 900px) {
  .fs .fs-title-grid { grid-template-columns: 1.1fr 0.9fr; }
}

/* Manual <br> controls the hero breaks; balance/max-width from the base sheet
   would re-wrap a line that fits, so both are cleared here. */
.fs .fs-abstract h1 { margin-bottom: var(--d2); text-wrap: normal; max-width: none; }
.fs .fs-abstract .fs-lead { margin-bottom: var(--d3); max-width: 42ch; }

/* Hero drawing as a framed plate on the sheet, so the right column is a
   deliberate figure rather than a diagram floating in empty space. */
.fs .fs-hero-plate {
  display: flex;
  flex-direction: column;
  border: var(--hair) solid var(--ink);
  background: var(--sheet);
}
.fs .fs-hero-plate::before,
.fs .fs-hero-plate::after {
  content: "";
  position: absolute;
  width: 14px; height: 14px;
  border: var(--hair) solid var(--ink);
  opacity: 0.5;
  pointer-events: none;
}
.fs .fs-hero-plate::before { top: 9px; left: 9px; border-right: none; border-bottom: none; }
.fs .fs-hero-plate::after { top: 9px; right: 9px; border-left: none; border-bottom: none; }
.fs .fs-hero-plate-art {
  flex: 1;
  display: grid;
  place-items: center;
  padding: var(--d4);
}
.fs .fs-hero-plate-art svg { width: 100%; }
.fs .fs-hero-plate .fs-figcap {
  margin: 0;
  padding: var(--d2) var(--d3);
  border-top: var(--hair) solid var(--ink);
}
.fs .fs-hero-plate .fs-figcap span { color: var(--ink-muted); font-size: var(--t-small); }

/* The plain-language 1-2-3, so a first-time visitor gets the whole idea before
   they read a word of the spec. Numerals sit in blueline chips like the drawing's
   own callouts, tying the reassurance back into the world. */
.fs .fs-steps {
  list-style: none;
  margin: 0 0 var(--d3);
  padding: 0;
  display: grid;
  gap: var(--d1);
}
@media (min-width: 520px) {
  .fs .fs-steps { grid-template-columns: repeat(3, 1fr); gap: var(--d2); }
}
.fs .fs-steps li {
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 0;
  overflow: hidden;
  border: var(--hair) solid var(--rule-strong);
  font-family: var(--letter);
  font-weight: var(--w-display);
  font-size: var(--t-small);
  line-height: var(--lh-heading);
  letter-spacing: var(--tr-callout);
  text-transform: uppercase;
  color: var(--ink);
}
/* Full-height number tab: fills the chip so one- and two-line labels read as one
   even row instead of a small square floating in a stretched box. */
.fs .fs-steps span {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 2.5rem;
  background: var(--blueline);
  color: #fff;
  font-size: var(--t-h3);
  font-weight: var(--w-display);
}
.fs .fs-steps em {
  display: flex;
  align-items: center;
  padding: var(--d1) var(--d2);
  font-style: normal;
}

/* In-prose links point in the proof color, matching the drawing's callouts. */
.fs p a, .fs .fs-claim p a, .fs .faq-item p a { color: var(--blueline); text-underline-offset: 2px; }
.fs p a:hover { color: var(--blueline-deep); }

.fs .fs-faq-link {
  display: inline-block;
  margin-top: var(--d2);
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-callout);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--blueline);
  text-decoration: none;
}
.fs .fs-faq-link:hover { color: var(--blueline-deep); text-decoration: underline; }

.fs .fs-actions { display: flex; flex-wrap: wrap; gap: var(--d1); align-items: center; }

.fs .fs-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--d1);
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-callout);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d2) var(--d3);
  border-radius: var(--radius);
  text-decoration: none;
  border: var(--hair) solid var(--ink);
  transition: background 0.2s var(--draw), color 0.2s var(--draw), transform 0.2s var(--draw);
}
.fs .fs-btn--primary { background: var(--blueline); border-color: var(--blueline); color: #fff; }
.fs .fs-btn--primary:hover { background: var(--blueline-deep); border-color: var(--blueline-deep); }
.fs .fs-btn--ghost { background: transparent; color: var(--ink); }
.fs .fs-btn--ghost:hover { background: var(--ink); color: var(--sheet); }
.fs .fs-btn:active { transform: translateY(1px); }

.fs .fs-note {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: var(--d2);
}

/* ── Figures ──────────────────────────────────────────────────────────────── */
.fs .fs-figure { position: relative; margin: 0; }
.fs .fs-figure svg { display: block; width: 100%; height: auto; overflow: visible; }

.fs .fig-line   { fill: none; stroke: var(--ink); stroke-width: 1.15; vector-effect: non-scaling-stroke; }
.fs .fig-hair   { fill: none; stroke: var(--ink); stroke-width: 0.6; opacity: 0.42; vector-effect: non-scaling-stroke; }
.fs .fig-solid  { fill: var(--ink); stroke: none; }
.fs .fig-lead   { fill: none; stroke: var(--blueline); stroke-width: 0.9; vector-effect: non-scaling-stroke; }
.fs .fig-dot    { fill: var(--blueline); stroke: none; }
.fs .fig-face   { fill: none; stroke: var(--ink); stroke-width: 0.55; opacity: 0.5; vector-effect: non-scaling-stroke; }
.fs .fig-wash   { fill: var(--blueline-wash); stroke: none; }
/* Solid body of the finished print — pale fill so it reads as a physical object
   rather than the wireframe model in the earlier step. */
.fs .fig-fill   { fill: var(--sheet-2); stroke: none; }
/* Same trick applied to a whole line-drawn group: the printed object's shapes
   get the pale body fill while keeping their ink outline. */
.fs .fig-solid .fig-line { fill: var(--sheet-2); }
/* Print-in-progress: the not-yet-printed top is a dashed ghost; the layer being
   laid right now is the one bright line. */
.fs .fig-ghost { stroke-dasharray: 4 5; opacity: 0.55; }
.fs .fig-layer { fill: none; stroke: var(--ink); stroke-width: 0.9; opacity: 0.62; vector-effect: non-scaling-stroke; }
.fs .fig-print-front { fill: none; stroke: var(--blueline); stroke-width: 2.4; stroke-linecap: round; vector-effect: non-scaling-stroke; }

.fs .fig-num {
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: 15px;
  letter-spacing: var(--tr-callout);
  fill: var(--blueline);
}
.fs .fig-label {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: 12px;
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  fill: var(--ink-muted);
}

.fs .fs-figno { white-space: nowrap; }

.fs .fs-figcap {
  display: flex;
  gap: var(--d2);
  align-items: baseline;
  margin-top: var(--d2);
  padding-top: var(--d1);
  border-top: var(--hair) solid var(--rule);
  color: var(--ink-muted);
}
.fs .fs-figcap b { color: var(--ink); font-weight: var(--w-strong); }

/* Strokes render as if drawn. Set complete by default; JS opts in to the draw. */
.fs .draws [class^="fig-"],
.fs .draws [class*=" fig-"] { stroke-dasharray: none; }
.fs .draws.is-armed .fig-line,
.fs .draws.is-armed .fig-hair,
.fs .draws.is-armed .fig-lead,
.fs .draws.is-armed .fig-face {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
}
.fs .draws.is-drawn .fig-line,
.fs .draws.is-drawn .fig-hair,
.fs .draws.is-drawn .fig-lead,
.fs .draws.is-drawn .fig-face {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 1.1s var(--draw) var(--d, 0s);
}
.fs .draws.is-armed .fig-num,
.fs .draws.is-armed .fig-label,
.fs .draws.is-armed .fig-dot,
.fs .draws.is-armed .fig-solid { opacity: 0; }
.fs .draws.is-drawn .fig-num,
.fs .draws.is-drawn .fig-label,
.fs .draws.is-drawn .fig-dot,
.fs .draws.is-drawn .fig-solid {
  opacity: 1;
  transition: opacity 0.5s var(--draw) 0.75s;
}

/* ── SHEET 2 — the register pair (the page's one authored motion) ─────────── */
.fs .fs-register { background: var(--sheet); }
.fs .fs-register-grid { display: grid; gap: var(--d5); padding-top: var(--d5); }
@media (min-width: 940px) {
  .fs .fs-register-grid { grid-template-columns: 0.92fr 1.08fr; align-items: start; }
}

.fs .fs-plate-stack {
  position: relative;
  aspect-ratio: 1 / 1;
  border: var(--hair) solid var(--ink);
  background: var(--sheet);
  overflow: hidden;
}
@media (min-width: 940px) {
  .fs .fs-plate-stack { position: sticky; top: 92px; }
}
/* corner registration ticks — a real sheet is registered, not rounded */
.fs .fs-plate-stack::before,
.fs .fs-plate-stack::after {
  content: "";
  position: absolute;
  width: 14px; height: 14px;
  border: var(--hair) solid var(--ink);
  opacity: 0.5;
  pointer-events: none;
}
.fs .fs-plate-stack::before { top: 8px; left: 8px; border-right: none; border-bottom: none; }
.fs .fs-plate-stack::after { bottom: 8px; right: 8px; border-left: none; border-top: none; }

.fs .fs-state {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--d4);
  opacity: 0;
  transition: opacity 0.55s var(--draw);
}
.fs .fs-state.is-live { opacity: 1; }
.fs .fs-state svg { max-height: 100%; }

.fs .fs-state-tag {
  position: absolute;
  left: 0; bottom: 0;
  display: flex;
  gap: var(--d2);
  align-items: baseline;
  padding: var(--d1) var(--d2);
  border-top: var(--hair) solid var(--ink);
  border-right: var(--hair) solid var(--ink);
  background: var(--sheet);
  color: var(--ink-muted);
}
.fs .fs-state-tag b { color: var(--ink); }

.fs .fs-spec-step {
  padding: var(--d6) 0 var(--d6) var(--d2);
  border-bottom: var(--hair) solid var(--rule);
}
/* Below the sticky breakpoint the plate scrolls away with the steps, so the
   viewport-tall gaps that pace the desktop scroll-lock become dead space.
   Tighten the steps into a readable list. */
@media (max-width: 939.98px) {
  .fs .fs-spec-step { padding-block: var(--d4); }
}
.fs .fs-spec-step:last-child { border-bottom: none; }
.fs .fs-spec-step h3 { margin-bottom: var(--d2); }
.fs .fs-spec-step .fs-figno {
  display: flex;
  align-items: center;
  gap: var(--d1);
  color: var(--ink-muted);
  margin-bottom: var(--d2);
  transition: color 0.35s var(--draw);
}
/* Register mark: hollow while the sheet is off register, filled when it locks.
   Text stays at full contrast throughout — the lock is signalled by the mark,
   the rule, and the plate swapping, never by dimming prose. */
.fs .fs-spec-step .fs-figno::before {
  content: "";
  width: 9px;
  height: 9px;
  border: 1px solid currentColor;
  background: transparent;
  transition: background 0.35s var(--draw), border-color 0.35s var(--draw);
}
.fs .fs-spec-step.is-locked .fs-figno { color: var(--blueline); }
.fs .fs-spec-step.is-locked .fs-figno::before { background: var(--blueline); border-color: var(--blueline); }
.fs .fs-spec-step { box-shadow: inset 3px 0 0 -2px transparent; transition: box-shadow 0.35s var(--draw); }
.fs .fs-spec-step.is-locked { box-shadow: inset 3px 0 0 -2px var(--blueline); }

/* ── SHEET 3 — photostat negative ─────────────────────────────────────────── */
.fs .fs-negative {
  background: var(--neg);
  color: var(--neg-line);
  border-bottom-color: var(--neg);
}
.fs .fs-negative h2, .fs .fs-negative h3 { color: var(--neg-line); }
.fs .fs-negative p { color: var(--neg-muted); }
.fs .fs-negative .fs-stamp { color: var(--neg-muted); border-bottom-color: rgba(251, 251, 250, 0.22); }
.fs .fs-negative .fs-stamp b { color: var(--neg-line); }
.fs .fs-negative .fig-line { stroke: var(--neg-line); }
.fs .fs-negative .fig-hair,
.fs .fs-negative .fig-face { stroke: var(--neg-line); opacity: 0.4; }
.fs .fs-negative .fig-solid { fill: var(--neg-line); }
.fs .fs-negative .fig-label { fill: var(--neg-muted); }
.fs .fs-negative .fig-lead { stroke: #8fb0ff; }
.fs .fs-negative .fig-num { fill: #8fb0ff; }
.fs .fs-negative .ref { color: #8fb0ff; }

.fs .fs-parties {
  display: grid;
  gap: 0;
  padding: var(--d5) 0 var(--d5);
}
@media (min-width: 860px) { .fs .fs-parties { grid-template-columns: repeat(3, 1fr); } }

.fs .fs-party {
  padding: var(--d3);
  border-top: var(--hair) solid rgba(251, 251, 250, 0.22);
}
@media (min-width: 860px) {
  .fs .fs-party { border-top: none; border-left: var(--hair) solid rgba(251, 251, 250, 0.22); }
  .fs .fs-party:first-child { border-left: none; padding-left: 0; }
  .fs .fs-party:last-child { padding-right: 0; }
}
.fs .fs-party .fs-figno { color: #8fb0ff; display: block; margin-bottom: var(--d2); }
.fs .fs-party svg { width: 100%; max-width: 190px; height: auto; margin-bottom: var(--d2); }
.fs .fs-party h3 { margin-bottom: var(--d1); }

.fs .fs-negative .fs-heading-block {
  display: grid;
  gap: var(--d4);
  align-items: end;
  padding: var(--d5) 0 0;
}
@media (min-width: 860px) {
  .fs .fs-negative .fs-heading-block { grid-template-columns: 1.15fr 1fr; }
}
.fs .fs-negative .fs-heading-block h2 { max-width: 15ch; }
.fs .fs-negative .fs-heading-block p { max-width: 44ch; }

/* ── SHEET 4 — the plate. The only full colour on the page. ───────────────── */
.fs .fs-plate-sheet { background: var(--ink); border-bottom-color: var(--ink); }
.fs .fs-plate-figure { position: relative; margin: 0; }
.fs .fs-plate-figure img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 78vh;
  object-fit: cover;
}
.fs .fs-plate-caption {
  position: absolute;
  left: 0; bottom: 0;
  max-width: min(46ch, 92%);
  padding: var(--d3);
  background: var(--sheet);
  border-top: var(--hair) solid var(--ink);
  border-right: var(--hair) solid var(--ink);
}
.fs .fs-plate-caption .fs-figno { display: block; color: var(--blueline); margin-bottom: var(--d1); }
.fs .fs-plate-caption h2 { font-size: var(--t-h2-sm); margin-bottom: var(--d1); }
.fs .fs-plate-caption p { font-size: var(--t-small); margin: 0; }

/* ── SHEET 5 — claims ─────────────────────────────────────────────────────── */
.fs .fs-claims-sheet { padding-bottom: var(--d5); }
/* padding-block, not padding-top: this grid is the last block in its sheet on
   about/faq/marketplace, and with no bottom padding its last line landed 1px
   above the next sheet's edge. */
.fs .fs-claims-grid { display: grid; gap: var(--d4); padding-block: var(--d5); }
@media (min-width: 900px) { .fs .fs-claims-grid { grid-template-columns: 0.8fr 1.2fr; } }

.fs .fs-claims { list-style: none; margin: 0; padding: 0; counter-reset: claim; }
.fs .fs-claim { border-top: var(--hair) solid var(--rule); }
.fs .fs-claim:last-child { border-bottom: var(--hair) solid var(--rule); }
.fs .fs-claim summary {
  display: grid;
  grid-template-columns: 2.6rem 1fr auto;
  gap: var(--d2);
  align-items: baseline;
  padding: var(--d2) 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-body);
  letter-spacing: var(--tr-callout);
  color: var(--ink);
}
.fs .fs-claim summary::-webkit-details-marker { display: none; }
.fs .fs-claim summary::before {
  counter-increment: claim;
  content: counter(claim, decimal-leading-zero) ".";
  font-size: var(--t-callout);
  letter-spacing: var(--tr-letter);
  color: var(--blueline);
  font-weight: var(--w-strong);
}
.fs .fs-claim summary::after {
  content: "+";
  font-size: var(--t-body);
  font-weight: var(--w-letter);
  color: var(--ink-muted);
  transition: transform 0.25s var(--draw);
}
.fs .fs-claim[open] summary::after { content: "\2013"; }
.fs .fs-claim summary:hover { color: var(--blueline); }
.fs .fs-claim > p {
  padding: 0 0 var(--d2) var(--d5);
  margin: 0;
  max-width: 62ch;
}

/* ── Commission — full-width call-to-action sheet ─────────────────────────── */
.fs .fs-commission-sheet { padding: var(--d5) 0; }
.fs .fs-closing {
  border: var(--hair) solid var(--ink);
  padding: var(--d4);
  background: var(--blueline-wash);
  display: grid;
  gap: var(--d4);
  align-items: center;
}
/* At sheet width the copy holds the left, the action anchors the right. */
@media (min-width: 720px) {
  .fs .fs-closing { grid-template-columns: minmax(0, 1fr) auto; }
}
.fs .fs-closing h2 { margin-bottom: var(--d1); font-size: var(--t-h2-sm); max-width: 22ch; }
.fs .fs-closing p { color: var(--ink); margin-bottom: 0; max-width: 58ch; }
.fs .fs-closing .fs-figno { display: block; color: var(--blueline); margin-bottom: var(--d2); }
.fs .fs-closing .fs-btn { justify-self: start; white-space: nowrap; }

/* ── Footer as the sheet's bottom title block ─────────────────────────────── */
.fs .site-footer {
  display: grid;
  /* wordmark pinned left, links centred across the full width by the flanking 1fr */
  grid-template-columns: 1fr auto 1fr;
  gap: 0;
  align-items: stretch;
  max-width: none;
  margin: 0;
  padding: 0;
  border: none;
  border-top: var(--hair) solid var(--ink);
  background: var(--sheet);
  color: var(--ink-muted);
}
.fs .site-footer .footer-wordmark { grid-column: 1; justify-self: start; }
/* Padding on a replaced element fights its intrinsic ratio; margin does not. */
.fs .site-footer .footer-wordmark {
  height: 16px;
  width: 81px;
  align-self: center;
  margin: var(--d2) var(--d3);
  opacity: 1;
  filter: grayscale(1);
}
.fs .fs-footer-links {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
}
.fs .fs-footer-links a:last-child { border-right: none; }
.fs .site-footer a {
  display: flex;
  align-items: center;
  padding: var(--d2);
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
  text-decoration: none;
  border-right: var(--hair) solid var(--rule);
}
.fs .site-footer a:hover { color: var(--blueline); }

/* ── Mobile ───────────────────────────────────────────────────────────────── */

/* The header collapses at 980, not 860. styles.css switches to the hamburger
   and its fixed drop-down index at max-width:980, so between 861 and 980 the
   sheet was still drawing a five-track desktop bar underneath an open phone
   menu. The bar's breakpoint moves to meet the one that was already there. */
@media (max-width: 980px) {
  .fs .nav-toggle { display: flex; align-items: center; }
  .fs .site-header {
    grid-template-columns: 1fr auto auto;
    grid-template-areas: "brand auth toggle" "nav nav nav";
  }
  .fs .brand { grid-area: brand; }
  .fs .nav-auth { grid-area: auth; }
  .fs .nav-user-chip { grid-area: auth; }
  .fs .nav-toggle { grid-area: toggle; }
  .fs .nav-cta { display: none; }
  .fs .nav-links {
    grid-area: nav;
    display: none;
    flex-direction: column;
    /* Opaque so the open menu never reads through to the sheet behind it. */
    background: var(--sheet);
    border-top: var(--hair) solid var(--ink);
  }
  .fs.nav-open .nav-links { display: flex; }
  .fs .nav-links a {
    border-right: none;
    border-left: none !important;
    border-bottom: var(--hair) solid var(--rule);
    padding: var(--d2) var(--gut);
  }
}

@media (max-width: 860px) {
  .fs .fs-plate-caption { position: static; max-width: none; border-right: none; }
  /* Portrait crop keeps the printer and the finished part in frame. */
  .fs .fs-plate-figure img { max-height: none; aspect-ratio: 4 / 3; object-position: 64% center; }
  /* Drawing labels are in user units, so they need bumping when the sheet shrinks. */
  .fs .fig-num { font-size: 21px; }
  .fs .fig-label { font-size: 18px; }
  .fs .fs-party svg .fig-num,
  .fs .fs-party svg .fig-label { font-size: 12px; }
  /* Footer stacks: wordmark over the centred links. */
  .fs .site-footer { grid-template-columns: 1fr; }
  .fs .site-footer .footer-wordmark { justify-self: center; }
  .fs .fs-footer-links { grid-column: 1; border-top: var(--hair) solid var(--rule); }
}

@media (max-width: 560px) {
  /* The sheet reads one step smaller on a phone. Move the two ladder rungs that
     sit either side of the base with it, so body/lead/base stay one height each
     instead of converging on 16 / 16.8 / 17 within a single paragraph block. */
  .fs {
    font-size: 16px;
    --t-body: 1rem;
    --t-lead: 1.0625rem;
  }
  .fs .fs-claim summary { grid-template-columns: 2.2rem 1fr auto; }
  .fs .fs-claim > p { padding-left: var(--d4); }
}

/* ── Reduced motion: every sheet permanently in register, all strokes drawn ── */
@media (prefers-reduced-motion: reduce) {
  .fs *, .fs *::before, .fs *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  .fs .draws.is-armed .fig-line,
  .fs .draws.is-armed .fig-hair,
  .fs .draws.is-armed .fig-lead,
  .fs .draws.is-armed .fig-face { stroke-dasharray: none; stroke-dashoffset: 0; }
  .fs .draws.is-armed .fig-num,
  .fs .draws.is-armed .fig-label,
  .fs .draws.is-armed .fig-dot,
  .fs .draws.is-armed .fig-solid { opacity: 1; }
  .fs .fs-spec-step { opacity: 1; }
}

/* ============================================================================
   COMPONENT LIBRARY — the functional-page UI, drawn as drafted spec.
   Loaded after styles.css; every rule is scoped to .fs so it overrides the old
   look by specificity (.fs .button beats .button) without touching live site/.
   The homepage (index.html) uses none of these classes, so it is unaffected.
   See DESIGN.md for the system these implement.
   ========================================================================== */

/* ── Neutralize the decorative background canvas ──────────────────────────── */
/* The drafting grid + figures replace it. app.js initMotionCanvases() skips any
   canvas whose computed display is none, so this needs no JS change. */
.fs canvas.motion-canvas { display: none !important; }

/* ── Shared page chrome carried over from styles.css ──────────────────────── */
/* Heroes lose their gradient/blur wrappers and read as a title sheet band. */
.fs .page-hero,
.fs .create-hero {
  position: relative;
  overflow: visible;
  isolation: auto;
  background: var(--sheet);
  border-bottom: var(--hair) solid var(--ink);
  padding: var(--d5) var(--gut) var(--d4);
}
.fs .page-hero.compact-hero { padding-block: var(--d4); }
.fs .page-hero > *,
.fs .create-hero > * { width: min(var(--sheet-max), 100%); margin-inline: auto; }

/* signal-label / eyebrow → the sheet's figno lettering */
.fs .signal-label {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  text-transform: uppercase;
  letter-spacing: var(--tr-letter);
  font-size: var(--t-letter);
  color: var(--blueline);
  margin: 0 0 var(--d2);
}
/* .page-hero h1 / .create-hero h1 used to restate the base heading rule with a
   line-height of 0.96 against the base 0.94 — one role, two leadings, split
   across pages by which selector happened to win. The base rule is the role. */

/* .lead was a second definition of .fs-lead differing by 0.02rem of size and
   0.02 of leading: invisible, and two names for one paragraph. */
.fs .lead,
.fs .fs-lead {
  font-family: var(--spec);
  font-size: var(--t-lead);
  font-weight: var(--w-spec-med);
  color: var(--ink-muted);
  line-height: var(--lh-spec);
}

/* A content section within a sheet-width column. */
.fs .section {
  width: min(var(--sheet-max), calc(100% - var(--gut) * 2));
  margin-inline: auto;
  padding-block: var(--d5);
  border-bottom: var(--hair) solid var(--rule);
}
.fs .section-heading h2,
.fs .split-section h2,
.fs .faq-strip h2,
.fs .proof-band h2 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); }
.fs .split-section { display: grid; gap: var(--d4); }
@media (min-width: 860px) { .fs .split-section { grid-template-columns: 1fr 1fr; align-items: start; } }
.fs .trust-grid { display: grid; gap: 0; }
@media (min-width: 760px) { .fs .trust-grid { grid-template-columns: repeat(3, 1fr); } }
.fs .trust-grid article {
  padding: var(--d3);
  border: var(--hair) solid var(--rule);
  margin: -0.5px 0 0 -0.5px;
  background: var(--sheet);
}
.fs .trust-grid h3, .fs .trust-grid article h3 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); margin-bottom: var(--d1); }

/* reveal entry fade is compatible with the world; keep it subtle. */
.fs .reveal { opacity: 0; transform: translateY(10px); transition: opacity 0.6s var(--draw), transform 0.6s var(--draw); }
.fs .reveal.is-visible { opacity: 1; transform: none; }

/* ── Buttons — every .button variant maps to the fs-btn grammar ───────────── */
.fs .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--d1);
  min-height: 0;
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-callout);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  line-height: 1;
  padding: var(--d2);
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  background: var(--sheet);
  color: var(--ink);
  box-shadow: none;
  transition: background 0.2s var(--draw), color 0.2s var(--draw), border-color 0.2s var(--draw), transform 0.2s var(--draw);
}
.fs .button-primary { background: var(--blueline); border-color: var(--blueline); color: #fff; box-shadow: none; }
.fs .button-primary:hover { background: var(--blueline-deep); border-color: var(--blueline-deep); }
.fs .button-light { background: var(--ink); border-color: var(--ink); color: var(--sheet); box-shadow: none; }
.fs .button-light:hover { background: #000; }
.fs .button-ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.fs .button-ghost:hover { background: var(--ink); color: var(--sheet); }
.fs .button:hover { transform: none; box-shadow: none; }
.fs .button:active { transform: translateY(1px); }
.fs .button:disabled { opacity: 0.46; }
/* On a negative band, buttons invert. */
.fs .fs-negative .button-light,
.fs .proof-band.fs-negative .button-light { background: var(--neg-line); border-color: var(--neg-line); color: var(--neg); }

/* ── Form controls — hairline title-block fields ──────────────────────────── */
.fs input[type="text"],
.fs input[type="email"],
.fs input[type="password"],
.fs input[type="number"],
.fs input[type="url"],
.fs input[type="search"],
.fs select,
.fs textarea {
  width: 100%;
  min-height: 46px;
  padding: var(--d1) var(--d2);
  font-family: var(--spec);
  font-weight: var(--w-spec-med);
  color: var(--ink);
  background: var(--sheet);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  box-shadow: none;
}
.fs textarea { min-height: 120px; resize: vertical; line-height: var(--lh-spec); }
.fs select { padding-right: var(--d3); cursor: pointer; }
.fs input::placeholder, .fs textarea::placeholder { color: var(--ink-muted); opacity: 0.6; }
.fs input:focus,
.fs select:focus,
.fs textarea:focus {
  outline: 2px solid var(--blueline);
  outline-offset: 1px;
  border-color: var(--blueline);
}
.fs input[type="range"] { width: 100%; accent-color: var(--blueline); }
.fs input[type="checkbox"], .fs input[type="radio"] { accent-color: var(--blueline); width: auto; min-height: 0; }

/* labels + field keys in title-block lettering */
.fs .field-label,
.fs label.field-label,
.fs .calc-field > label,
.fs .mk-field label,
.fs .mk-fieldset legend {
  display: block;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: var(--d2) 0 var(--d1);
}

/* ── Status pills → title-block stamps ────────────────────────────────────── */
.fs .job-status {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  padding: var(--d1);
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink);
  background: var(--sheet-2);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  box-shadow: none;
}
.fs .job-status.active,
.fs .job-status.routing { color: var(--blueline); border-color: var(--blueline); background: var(--blueline-wash); }
.fs .job-status.done,
.fs .job-status.delivered,
.fs .job-status.ready { color: #fff; background: var(--ink); border-color: var(--ink); }
.fs .job-status.quote { color: var(--ink); background: var(--sheet); border-style: dashed; }

/* Framed-plate helper: the corner-tick border reused for repeated objects. */
.fs .job-card,
.fs .price-card,
.fs .maker-job-card,
.fs .dash-job-card,
.fs .control-panel,
.fs .model-panel,
.fs .quote-panel,
.fs .calc-inputs,
.fs .calc-breakdown {
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  background: var(--sheet);
  box-shadow: none;
}

/* ============================================================================
   MARKETPLACE
   ========================================================================== */
.fs .filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--d1);
  padding: var(--d2) 0;
  border-bottom: var(--hair) solid var(--ink);
  margin-bottom: var(--d3);
}
.fs .filter-pill {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1) var(--d2);
  color: var(--ink-muted);
  background: var(--sheet);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  cursor: pointer;
  transition: color 0.18s var(--draw), background 0.18s var(--draw), border-color 0.18s var(--draw);
}
.fs .filter-pill:hover { color: var(--ink); border-color: var(--ink); }
.fs .filter-pill.is-active { color: #fff; background: var(--blueline); border-color: var(--blueline); }
.fs .filter-divider { width: var(--hair); align-self: stretch; background: var(--rule); margin: 0 var(--d1); }
.fs .filter-sort {
  min-height: 0;
  padding: var(--d1) var(--d3) var(--d1) var(--d1);
  font-family: var(--letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
}
.fs .filter-count {
  margin-left: auto;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.fs .job-grid {
  display: grid;
  gap: var(--d2);
  /* 260px gave four columns at sheet width, and a job blurb came out at 26ch —
     four words a line. DESIGN.md's rule is that a column narrower than the
     measure is the column being wrong, so the cards are three-up, on the same
     cadence as the parties and the price plans. */
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
}
.fs .job-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--d1);
  padding: var(--d3);
  cursor: pointer;
  transition: border-color 0.18s var(--draw);
}
.fs .job-card:hover { border-color: var(--blueline); }
.fs .job-card-title { font-family: var(--letter); font-weight: var(--w-strong); text-transform: uppercase; letter-spacing: var(--tr-callout); color: var(--ink); font-size: var(--t-body); margin: 0; }
.fs .job-card p { color: var(--ink-muted); margin: 0; font-size: var(--t-small); }
.fs .job-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--d1) var(--d1);
  margin-top: auto;
  padding-top: var(--d1);
  border-top: var(--hair) solid var(--rule);
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.fs .job-view-btn {
  align-self: flex-start;
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1) var(--d2);
  color: var(--blueline);
  background: transparent;
  border: var(--hair) solid var(--blueline);
  border-radius: var(--radius);
  cursor: pointer;
}
.fs .job-view-btn:hover { background: var(--blueline); color: #fff; }
.fs .no-jobs-msg { color: var(--ink-muted); font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-callout); }

/* Detail panel — a spec sheet sliding over the grid. */
.fs .detail-overlay { background: rgba(20, 19, 15, 0.4); backdrop-filter: none; }
.fs .detail-panel {
  width: min(500px, 100vw);
  background: var(--sheet);
  border-left: var(--hair) solid var(--ink);
  box-shadow: none;
}
.fs .detail-header { background: var(--sheet); border-bottom: var(--hair) solid var(--ink); }
.fs .detail-job-title { font-family: var(--letter); text-transform: uppercase; color: var(--ink); }
.fs .detail-close {
  width: 38px; height: 38px;
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  background: var(--sheet);
  color: var(--ink);
  cursor: pointer;
}
.fs .detail-close:hover { background: var(--ink); color: var(--sheet); }
.fs .detail-body { padding: var(--d3); display: flex; flex-direction: column; gap: var(--d2); }
.fs .detail-job-desc { color: var(--ink-muted); }
.fs .detail-meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border: var(--hair) solid var(--rule); }
.fs .detail-meta-item {
  display: flex;
  flex-direction: column;
  gap: var(--d1);
  padding: var(--d1) var(--d2);
  border: var(--hair) solid var(--rule);
  margin: -0.5px 0 0 -0.5px;
}
.fs .detail-meta-item span {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.fs .detail-meta-item strong { font-family: var(--spec); font-weight: var(--w-letter); color: var(--ink); font-size: var(--t-small); }
.fs .detail-divider { height: var(--hair); background: var(--ink); margin: var(--d1) 0; }
.fs .bid-form-section h3 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); margin-bottom: var(--d2); }
.fs .bid-form { display: flex; flex-direction: column; gap: var(--d1); }
.fs .bid-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--d1); }
.fs .bid-field { display: flex; flex-direction: column; }
.fs .bid-field label {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: var(--d1);
}
.fs .bid-submitted-msg {
  padding: var(--d2);
  border: var(--hair) solid var(--blueline);
  background: var(--blueline-wash);
  color: var(--ink);
  font-family: var(--spec);
  font-size: var(--t-small);
}

/* Toast — a small title-block stamp. */
.fs .pb-toast {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  color: var(--sheet);
  background: var(--ink);
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: none;
}

/* ============================================================================
   CREATE — the drafting bench (restyle in place)
   ========================================================================== */
.fs .studio-layout {
  width: min(var(--sheet-max), calc(100% - var(--gut) * 2));
  margin-inline: auto;
  display: grid;
  gap: var(--d2);
  padding-block: var(--d4);
}
@media (min-width: 960px) {
  .fs .studio-layout { grid-template-columns: 0.9fr 1.2fr 0.9fr; align-items: start; }
  /* No model yet → the output panel is not in the flow, so close the gap and
     let the two remaining cards share one height. Sticky and the older
     full-width quote row are what produced the stray scroll: two plates of
     different heights, each parked against the bar, on a page barely taller
     than the viewport. Matched plates have nothing to scroll past. */
  .fs .studio-layout:not(.has-output) { grid-template-columns: 1fr 1fr; align-items: stretch; }
  .fs .studio-layout:not(.has-output) > * { position: static; grid-column: auto; }
}
.fs .model-panel[hidden] { display: none; }
.fs .control-panel,
.fs .model-panel,
.fs .quote-panel { padding: var(--d3); display: flex; flex-direction: column; }
.fs .panel-title { display: flex; flex-direction: column; gap: 0.2rem; margin-bottom: var(--d2); padding-bottom: var(--d1); border-bottom: var(--hair) solid var(--rule); }
.fs .panel-title > span {
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--blueline);
}
.fs .panel-title h2 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); font-size: var(--t-h3); }

/* Mode tabs / segmented control → sheet index tabs */
.fs .mode-tabs { display: flex; gap: 0; border: var(--hair) solid var(--ink); border-radius: var(--radius); overflow: hidden; margin-bottom: var(--d2); }
.fs .mode-tab {
  flex: 1;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1);
  color: var(--ink-muted);
  background: var(--sheet);
  border: none;
  border-right: var(--hair) solid var(--ink);
  cursor: pointer;
}
.fs .mode-tab:last-child { border-right: none; }
.fs .mode-tab.is-active { color: #fff; background: var(--blueline); }

.fs .upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--d1);
  padding: var(--d3);
  text-align: center;
  border: var(--hair) dashed var(--rule-strong);
  border-radius: var(--radius);
  background: var(--sheet-2);
  cursor: pointer;
  transition: border-color 0.18s var(--draw);
}
.fs .upload-zone:hover { border-color: var(--blueline); }
.fs .upload-zone input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.fs .upload-glyph { font-size: var(--t-h2-sm); color: var(--blueline); line-height: 1; }
.fs #upload-label { font-family: var(--letter); font-weight: var(--w-letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-callout); color: var(--ink); }
.fs .upload-zone small { font-family: var(--letter); letter-spacing: var(--tr-letter); text-transform: uppercase; font-size: var(--t-micro); color: var(--ink-muted); }

.fs .range-grid { display: grid; gap: var(--d2); margin-top: var(--d1); }
.fs .range-grid label { display: grid; gap: var(--d1); }
.fs .range-grid label > span,
.fs .compute-options label > span { font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-letter); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .range-grid strong { font-family: var(--letter); font-variant-numeric: tabular-nums; color: var(--ink); font-size: var(--t-small); }

.fs .viewer-shell {
  position: relative;
  min-height: 380px;
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  background: var(--sheet-2);
  overflow: hidden;
  aspect-ratio: 1.34;
}
.fs .viewer-badge {
  position: absolute;
  left: 0.6rem; top: 0.6rem;
  padding: var(--d1);
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  color: var(--sheet);
  background: var(--ink);
  border-radius: var(--radius);
}
.fs .viewer-help { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-micro); color: var(--ink-muted); }
.fs .generator-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0;
  margin-top: var(--d2);
  border: var(--hair) solid var(--rule);
}
.fs .generator-strip > div { padding: var(--d1); border: var(--hair) solid var(--rule); margin: -0.5px 0 0 -0.5px; }
.fs .generator-strip span { display: block; font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .generator-strip strong { font-family: var(--spec); font-size: var(--t-callout); color: var(--ink); }

.fs .worker-panel { margin-top: var(--d2); padding-top: var(--d2); border-top: var(--hair) solid var(--rule); }
.fs .worker-actions { margin-top: var(--d2); }
.fs .model-links { margin-top: var(--d1); display: flex; flex-wrap: wrap; gap: var(--d1); }
.fs .video-progress { margin-top: var(--d2); }
.fs .video-progress-track { height: 8px; background: var(--sheet-2); border: var(--hair) solid var(--rule-strong); border-radius: var(--radius); overflow: hidden; }
/* scaleX rather than width: the fill is a solid colour, so scaling is visually
   identical and the transition composites instead of laying out. */
.fs .video-progress-fill {
  height: 100%;
  width: 100%;
  background: var(--blueline);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.3s var(--draw);
}
@media (prefers-reduced-motion: reduce) {
  .fs .video-progress-fill { transition: none; }
}

.fs .quote-total { font-family: var(--letter); font-weight: var(--w-display); font-size: var(--t-h2-sm); color: var(--ink); line-height: 1; }
.fs .quote-panel .signal-label { margin-top: var(--d1); }
.fs .calc-rows { display: flex; flex-direction: column; margin: var(--d2) 0; border-top: var(--hair) solid var(--rule); }
.fs .calc-row {
  display: flex;
  justify-content: space-between;
  gap: var(--d2);
  padding: var(--d1) 0;
  border-bottom: var(--hair) solid var(--rule);
  font-family: var(--spec);
  font-size: var(--t-small);
  color: var(--ink-muted);
}
.fs .calc-row span:last-child { font-family: var(--letter); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: var(--w-letter); }
.fs .calc-discount, .fs .calc-row .calc-discount { color: var(--blueline); }
.fs .q-selects { margin-top: var(--d1); }
.fs .field-label-strong { font-weight: 800; color: var(--ink); }
.fs .material-row { display: flex; gap: var(--d1); margin: var(--d2) 0; }
.fs .material {
  display: inline-flex;
  align-items: center;
  gap: var(--d1);
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1) var(--d2);
  color: var(--ink-muted);
  background: var(--sheet);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  cursor: pointer;
}
.fs .material.is-selected { color: var(--ink); border-color: var(--blueline); box-shadow: inset 0 -3px 0 -1px var(--blueline); }
/* Material keys, in the sheet's own grammar. styles.css gave these three an
   emerald, an orange and a blue fill — two hues this world does not have, on
   10px chips whose label already says PLA / Resin / Nylon. Section hatching
   carries the distinction instead: solid, hatched, hollow. */
.fs .material .swatch {
  width: 10px; height: 10px;
  border-radius: 0;
  border: var(--hair) solid var(--ink);
  background: var(--sheet);
}
.fs .material .swatch-cyan { background: var(--ink); }
.fs .material .swatch-amber {
  background: repeating-linear-gradient(
    45deg, var(--ink) 0 1px, var(--sheet) 1px 3px
  );
}
.fs .material .swatch-blue { background: var(--sheet); }
.fs .quote-panel .button { width: 100%; margin-top: var(--d1); }
.fs .small-note { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-letter); color: var(--ink-muted); margin-top: var(--d1); }
.fs .small-note strong { color: var(--ink); }

/* ============================================================================
   MAKERS
   ========================================================================== */
.fs .maker-onboard { width: min(var(--sheet-max), calc(100% - var(--gut) * 2)); margin-inline: auto; padding-block: var(--d4); }
.fs .onboard-header { margin-bottom: var(--d3); }
.fs .onboard-header h2, .fs .feed-header h2 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); }
.fs .maker-form { border: var(--hair) solid var(--ink); border-radius: var(--radius); padding: var(--d3); background: var(--sheet); display: flex; flex-direction: column; gap: var(--d1); }
.fs .form-error { padding: var(--d1) var(--d2); border: var(--hair) solid var(--blueline); background: var(--blueline-wash); color: var(--ink); font-size: var(--t-callout); }
.fs .mk-field { display: flex; flex-direction: column; }
.fs .mk-fieldset { border: none; padding: 0; margin: var(--d1) 0; }
.fs .mk-fieldset legend { padding: 0; margin-bottom: var(--d1); }
.fs .mk-type-grid { display: grid; gap: var(--d1); }
@media (min-width: 620px) { .fs .mk-type-grid { grid-template-columns: repeat(3, 1fr); } }
.fs .mk-type-card { position: relative; cursor: pointer; }
.fs .mk-type-card input[type="radio"] { position: absolute; opacity: 0; }
.fs .mk-type-inner { display: block; height: 100%; padding: var(--d2); border: var(--hair) solid var(--rule-strong); border-radius: var(--radius); background: var(--sheet); transition: border-color 0.18s var(--draw); }
.fs .mk-type-card input:checked + .mk-type-inner { border-color: var(--blueline); box-shadow: inset 0 -3px 0 -1px var(--blueline); }
.fs .mk-type-inner strong { display: block; font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-callout); color: var(--ink); margin-bottom: var(--d1); }
.fs .mk-type-inner span { font-family: var(--spec); font-size: var(--t-callout); color: var(--ink-muted); line-height: var(--lh-spec); }
.fs .mk-check-grid { display: flex; flex-wrap: wrap; gap: var(--d1); }
.fs .mk-check { cursor: pointer; }
.fs .mk-check input[type="checkbox"] { position: absolute; opacity: 0; }
.fs .mk-check span {
  display: inline-flex;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1) var(--d2);
  color: var(--ink-muted);
  background: var(--sheet);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
}
.fs .mk-check:has(input:checked) span { color: #fff; background: var(--blueline); border-color: var(--blueline); }
.fs .mk-row { display: grid; gap: var(--d2); }
@media (min-width: 620px) { .fs .mk-row { grid-template-columns: 1fr 1fr; } }
.fs .mk-rate-wrap { display: flex; align-items: center; border: var(--hair) solid var(--rule-strong); border-radius: var(--radius); overflow: hidden; }
.fs .mk-rate-wrap:focus-within { border-color: var(--blueline); }
.fs .mk-rate-prefix, .fs .mk-rate-suffix { padding: 0 var(--d1); font-family: var(--letter); color: var(--ink-muted); background: var(--sheet-2); align-self: stretch; display: flex; align-items: center; }
.fs .mk-rate-wrap input { border: none; min-height: 44px; }
.fs .mk-rate-wrap input:focus { outline: none; }
.fs .mk-hint, .fs .calc-hint { font-family: var(--spec); font-size: var(--t-callout); color: var(--ink-muted); margin: var(--d1) 0 0; }
.fs .mk-submit { margin-top: var(--d2); align-self: flex-start; }
.fs .feed-header { display: flex; justify-content: space-between; align-items: flex-end; gap: var(--d2); flex-wrap: wrap; margin-bottom: var(--d2); }
.fs .maker-feed { display: grid; gap: var(--d2); grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.fs .maker-job-card { display: flex; flex-direction: column; gap: var(--d1); padding: var(--d3); }
.fs .maker-card-top { display: flex; justify-content: space-between; align-items: center; gap: var(--d1); }
.fs .maker-card-age { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-micro); color: var(--ink-muted); }
.fs .maker-card-title { font-family: var(--letter); text-transform: uppercase; color: var(--ink); font-size: var(--t-body); margin: 0; }
.fs .maker-card-desc { color: var(--ink-muted); font-size: var(--t-small); margin: 0; }
.fs .maker-card-chips { display: flex; flex-wrap: wrap; gap: var(--d1) var(--d1); font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .maker-bid-row { display: flex; justify-content: space-between; align-items: center; gap: var(--d2); margin-top: auto; padding-top: var(--d2); border-top: var(--hair) solid var(--rule); }
.fs .maker-bid-label { display: block; font-family: var(--letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .maker-bid-range { font-family: var(--letter); font-weight: var(--w-display); color: var(--ink); }
.fs .maker-bid-btn { flex-shrink: 0; }
.fs .feed-empty, .fs .no-jobs-msg { color: var(--ink-muted); }
.fs .proof-band { display: flex; justify-content: space-between; align-items: center; gap: var(--d3); flex-wrap: wrap; }

/* ============================================================================
   DASHBOARD (restyle in place, CSS-first)
   ========================================================================== */
.fs .dashboard-section { width: min(var(--sheet-max), calc(100% - var(--gut) * 2)); margin-inline: auto; padding-block: var(--d4); }
.fs .dash-tabs { display: flex; gap: 0; border: var(--hair) solid var(--ink); border-radius: var(--radius); overflow: hidden; margin-bottom: var(--d2); }
.fs .dash-tab {
  flex: 1;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d2) var(--d1);
  color: var(--ink-muted);
  background: var(--sheet);
  border: none;
  border-right: var(--hair) solid var(--ink);
  cursor: pointer;
}
.fs .dash-tab:last-child { border-right: none; }
.fs .dash-tab.is-active { color: #fff; background: var(--blueline); }
.fs .dash-tab-intro { margin-bottom: var(--d2); color: var(--ink-muted); }
.fs .dash-loading, .fs .dash-empty { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-callout); color: var(--ink-muted); }
.fs .dash-empty-link { color: var(--blueline); text-decoration: none; }
.fs .dash-grid { display: grid; gap: var(--d2); grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.fs .dash-job-card { padding: var(--d3); }
.fs .dash-job-header { display: flex; flex-direction: column; gap: var(--d1); }
.fs .dash-job-top { display: flex; align-items: center; gap: var(--d1); flex-wrap: wrap; }
.fs .dash-job-date { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-micro); color: var(--ink-muted); margin-left: auto; }
.fs .dash-job-title { font-family: var(--letter); text-transform: uppercase; color: var(--ink); font-size: var(--t-body); margin: 0; }
.fs .dash-job-meta { display: flex; flex-wrap: wrap; gap: var(--d1) var(--d1); font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-letter); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .dash-chip { padding: 0.15rem var(--d1); border: var(--hair) solid var(--rule-strong); border-radius: var(--radius); }
.fs .dash-expand-btn {
  align-self: flex-start;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1);
  color: var(--ink);
  background: var(--sheet-2);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  cursor: pointer;
}
.fs .dash-expand-arrow { color: var(--blueline); }
.fs .dash-bids-panel { margin-top: var(--d2); padding-top: var(--d2); border-top: var(--hair) solid var(--rule); }
.fs .dash-bids-header, .fs .dash-bid-row { display: grid; grid-template-columns: 1.4fr 0.7fr 0.5fr auto; gap: var(--d1); align-items: center; }
.fs .dash-bids-header { font-family: var(--letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); padding-bottom: var(--d1); border-bottom: var(--hair) solid var(--rule); }
.fs .dash-bid-row { padding: var(--d1) 0; border-bottom: var(--hair) solid var(--rule); }
.fs .dash-bid-maker { font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-callout); color: var(--ink); font-weight: var(--w-letter); }
.fs .dash-bid-specialty { font-family: var(--letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); display: block; }
.fs .dash-bid-price { font-family: var(--letter); font-weight: var(--w-display); color: var(--ink); }
.fs .dash-bid-days { font-family: var(--letter); color: var(--ink-muted); }
.fs .dash-bid-note, .fs .dash-bid-note-display { grid-column: 1 / -1; font-family: var(--spec); font-size: var(--t-callout); color: var(--ink-muted); }
.fs .dash-accept-btn { padding: var(--d1) var(--d2); }
.fs .dash-accepted-badge { font-family: var(--letter); font-weight: var(--w-strong); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--blueline); border: var(--hair) solid var(--blueline); padding: 0.2rem var(--d1); border-radius: var(--radius); }
.fs .dash-no-bids { font-family: var(--spec); color: var(--ink-muted); font-size: var(--t-callout); }
.fs .dash-share-card { display: flex; flex-wrap: wrap; align-items: center; gap: var(--d1); padding: var(--d2); border: var(--hair) solid var(--blueline); background: var(--blueline-wash); border-radius: var(--radius); margin: var(--d1) 0; }
.fs .dash-share-label { font-family: var(--letter); font-weight: var(--w-strong); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-letter); color: var(--ink); }

/* Accept modal — inherits .auth-modal styling below (dashboard.js sets both classes). */
.fs .accept-title { font-family: var(--letter); text-transform: uppercase; color: var(--ink); margin: var(--d1) 0 var(--d2); }
.fs .accept-details { border: var(--hair) solid var(--rule); margin: var(--d2) 0; }
.fs .accept-row { display: flex; justify-content: space-between; gap: var(--d2); padding: var(--d1); border-bottom: var(--hair) solid var(--rule); font-family: var(--spec); font-size: var(--t-small); color: var(--ink-muted); }
.fs .accept-row:last-child { border-bottom: none; }
.fs .accept-row strong { color: var(--ink); font-family: var(--letter); }
.fs .accept-note { flex-direction: column; }
.fs .accept-info { font-family: var(--spec); font-size: var(--t-callout); color: var(--ink-muted); }
.fs .accept-actions { display: flex; gap: var(--d1); margin-top: var(--d2); }
.fs .accept-error { color: var(--blueline); font-size: var(--t-callout); margin-top: var(--d1); }

/* ============================================================================
   PRICING
   ========================================================================== */
.fs .price-grid { display: grid; gap: 0; margin-block: var(--d3); }
@media (min-width: 760px) { .fs .price-grid { grid-template-columns: repeat(3, 1fr); } }
.fs .price-card { padding: var(--d3); margin: -0.5px 0 0 -0.5px; }
.fs .price-card.featured { border-color: var(--blueline); box-shadow: inset 0 -4px 0 -1px var(--blueline); }
.fs .price-card h2 { font-family: var(--letter); font-weight: var(--w-display); color: var(--ink); font-size: var(--t-h2-sm); margin: var(--d1) 0; }
.fs .price-card p { color: var(--ink-muted); }
.fs .calc-section { width: min(var(--sheet-max), calc(100% - var(--gut) * 2)); margin-inline: auto; padding-block: var(--d4); border-bottom: var(--hair) solid var(--rule); }
.fs .calc-header { margin-bottom: var(--d2); }
.fs .calc-header h2 { font-family: var(--letter); text-transform: uppercase; color: var(--ink); }
.fs .calc-layout { display: grid; gap: var(--d3); }
@media (min-width: 860px) { .fs .calc-layout { grid-template-columns: 1fr 1fr; align-items: start; } }
.fs .calc-inputs, .fs .calc-breakdown { padding: var(--d3); }
.fs .calc-field { margin-bottom: var(--d2); }
.fs .calc-field-header { display: flex; justify-content: space-between; align-items: baseline; }
.fs .calc-val { font-family: var(--letter); font-weight: var(--w-display); color: var(--blueline); font-variant-numeric: tabular-nums; }
.fs .calc-slider { width: 100%; accent-color: var(--blueline); }
.fs .calc-slider-ticks { display: flex; justify-content: space-between; font-family: var(--letter); font-size: var(--t-micro); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); margin-top: var(--d1); }
.fs .calc-weight-line { font-family: var(--letter); font-weight: var(--w-letter); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-letter); color: var(--ink-muted); padding-bottom: var(--d1); border-bottom: var(--hair) solid var(--ink); margin-bottom: var(--d1); }
.fs .calc-total-row { display: flex; justify-content: space-between; align-items: baseline; gap: var(--d2); padding-top: var(--d2); margin-top: var(--d1); border-top: var(--hair) solid var(--ink); font-family: var(--letter); text-transform: uppercase; letter-spacing: var(--tr-callout); color: var(--ink); }
.fs .calc-total-num { font-weight: var(--w-display); font-size: var(--t-h2-sm); font-variant-numeric: tabular-nums; }
.fs .calc-disclaimer { font-family: var(--spec); font-size: var(--t-callout); color: var(--ink-muted); margin-top: var(--d2); }
.fs .faq-strip { width: min(var(--sheet-max), calc(100% - var(--gut) * 2)); margin-inline: auto; padding-block: var(--d4); }
.fs .faq-strip-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--d2); flex-wrap: wrap; margin-bottom: var(--d2); }
.fs .faq-strip-all { font-family: var(--letter); font-weight: var(--w-strong); text-transform: uppercase; letter-spacing: var(--tr-letter); font-size: var(--t-letter); color: var(--blueline); text-decoration: none; }
.fs .faq-list { border-top: var(--hair) solid var(--rule); }
.fs .faq-item { border-bottom: var(--hair) solid var(--rule); }
.fs .faq-item summary { list-style: none; cursor: pointer; padding: var(--d2) 0; font-family: var(--letter); font-weight: var(--w-strong); text-transform: uppercase; letter-spacing: var(--tr-heading); color: var(--ink); display: flex; justify-content: space-between; gap: var(--d2); }
.fs .faq-item summary::-webkit-details-marker { display: none; }
.fs .faq-item summary::after { content: "+"; color: var(--ink-muted); }
.fs .faq-item[open] summary::after { content: "\2013"; }
.fs .faq-item p { padding: 0 0 var(--d2); color: var(--ink-muted); }

/* ============================================================================
   AUTH MODAL — injected by auth.js; styled by ID/class so it inherits the sheet.
   Also serves dashboard.js's accept modal (class="auth-modal accept-modal").
   ========================================================================== */
.fs .auth-overlay { position: fixed; inset: 0; z-index: 80; display: none; background: rgba(20, 19, 15, 0.4); backdrop-filter: none; }
.fs .auth-overlay.is-open { display: block; }
.fs .auth-modal {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -48%);
  z-index: 81;
  display: none;
  width: min(420px, calc(100vw - 2rem));
  max-height: 90vh;
  overflow-y: auto;
  padding: var(--d3);
  background: var(--sheet);
  border: var(--hair) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: none;
}
.fs .auth-modal.is-open { display: block; }
.fs .auth-modal h2, .fs .auth-modal .signal-label { color: var(--ink); }
.fs .auth-modal h2 { font-family: var(--letter); text-transform: uppercase; }
.fs .auth-tabs { display: flex; gap: 0; border: var(--hair) solid var(--ink); border-radius: var(--radius); overflow: hidden; margin: var(--d2) 0; }
.fs .auth-tab {
  flex: 1;
  font-family: var(--letter);
  font-weight: var(--w-letter);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  padding: var(--d1);
  color: var(--ink-muted);
  background: var(--sheet);
  border: none;
  border-right: var(--hair) solid var(--ink);
  cursor: pointer;
}
.fs .auth-tab:last-child { border-right: none; }
.fs .auth-tab.is-active { color: #fff; background: var(--blueline); }
.fs .auth-form { display: flex; flex-direction: column; gap: var(--d1); }
.fs .auth-form label { font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-letter); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); margin: var(--d1) 0 var(--d1); display: block; }
.fs .auth-submit, .fs #auth-submit { width: 100%; margin-top: var(--d2); }
.fs .auth-link { background: none; border: none; padding: 0; color: var(--blueline); font: inherit; cursor: pointer; text-decoration: underline; }
.fs .auth-error, .fs #auth-error { color: var(--blueline); font-size: var(--t-callout); }

/* Signed-in chip injected into the header. */
.fs .nav-user-chip {
  display: flex;
  align-items: center;
  gap: var(--d1);
  padding: 0 var(--d2);
  border-left: var(--hair) solid var(--ink);
}
.fs .nav-user-label { font-family: var(--letter); font-weight: var(--w-letter); font-size: var(--t-letter); letter-spacing: var(--tr-letter); text-transform: uppercase; color: var(--ink-muted); }
.fs .nav-account, .fs .nav-signout {
  font-family: var(--letter);
  font-weight: var(--w-strong);
  font-size: var(--t-letter);
  letter-spacing: var(--tr-letter);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  background: none;
  border: none;
  cursor: pointer;
}
.fs .nav-account:hover, .fs .nav-signout:hover { color: var(--blueline); }

/* ── styles.css literal-value resets ─────────────────────────────────────────
   The token remap at the top of this file catches everything styles.css sets
   through a var(). These are the declarations it hard-codes, plus the one place
   an unmatched box-model property survived. Each was verified in the browser.

   ponytail: three declarations, not a stylesheet rewrite. Goes away with
   styles.css. */

/* Emerald halo under the primary CTA — the literal that outlived the migration,
   on all nine pages. styles.css:198 sets background+color+box-shadow; the
   .fs rule above only replaced the first two. */
.fs .nav-cta,
.fs .button-primary { box-shadow: none; }

/* styles.css:798 sets `bottom`, this file's rule sets `top`. Both applied, so
   the badge stretched the full height of the viewer stage (126x356px). */
.fs .viewer-badge { bottom: auto; }

/* makers.html puts .proof-band inside a negative sheet, but `.fs .proof-band h2`
   sets ink and lands later in this file than `.fs .fs-negative h2` — so the
   band's headline rendered near-black on slate at 1.8:1. Restate the negative
   world at a specificity that wins, and drop the band's own ground so it reads
   as part of the sheet rather than a card sitting on it. */
.fs .fs-negative .proof-band { background: transparent; color: var(--neg-line); }
.fs .fs-negative .proof-band h2 { color: var(--neg-line); }
.fs .fs-negative .proof-band p { color: var(--neg-muted); }

/* ── Target size ─────────────────────────────────────────────────────────────
   These controls sized themselves from lettering + padding and landed at 31-38px
   on touch. The lettering stays; the box grows to the 44px floor around it, so
   the drafting proportions read the same and the tap area is honest.
   Inline links inside running copy are deliberately excluded — WCAG 2.5.8
   exempts them, and padding them out would break the text block. */
.fs .filter-pill,
.fs .job-view-btn,
.fs .dash-tab,
.fs .auth-tab,
.fs .auth-close,
.fs .detail-close,
.fs .filter-sort,
.fs .mk-check span,
.fs .button {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.fs .auth-close,
.fs .detail-close { min-width: 44px; }

/* Standalone links that sit on their own line rather than inside running copy —
   the 2.5.8 inline exemption does not cover these, and they were 15-21px tall. */
.fs .fs-faq-link,
.fs .faq-strip-all,
.fs .auth-link,
.fs .dash-empty-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* The checkbox is opacity:0 but still focusable and hit-testable at its intrinsic
   13x14. Stretch it over its label so pointer and focus agree on the target. */
.fs .mk-check { position: relative; display: inline-block; }
.fs .mk-check input[type="checkbox"] { inset: 0; width: 100%; height: 100%; margin: 0; }

/* ── Sliders ─────────────────────────────────────────────────────────────────
   A 4px-tall range input is a 4px-tall drag target, so the box is 44px. But the
   box cannot simply be made taller: styles.css paints the track as the input's
   own background, so a 44px box painted a 4px track's grey as a solid slab.
   The track moves to its pseudo-element and the box goes transparent.

   The thumb is a square, not the inherited 18px circle with a drop shadow. This
   sheet has corners and no shadows; a slider pointer is a machined block. */
.fs input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  height: 44px;
  background: transparent;
  cursor: pointer;
}
.fs input[type="range"]::-webkit-slider-runnable-track {
  height: 2px;
  background: var(--rule-strong);
  border-radius: 0;
}
.fs input[type="range"]::-moz-range-track {
  height: 2px;
  background: var(--rule-strong);
  border-radius: 0;
}
.fs input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -6px;              /* centre the block on the 2px rule */
  border-radius: 0;
  background: var(--blueline);
  box-shadow: none;
}
.fs input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 0;
  background: var(--blueline);
}
.fs input[type="range"]:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--blueline); outline-offset: 2px; }

/* ── Form controls: the 16px floor ───────────────────────────────────────────
   iOS Safari zooms the whole viewport when a control smaller than 16px takes
   focus. Eighteen of thirty-four controls sat at 11.2-15.2px, so every tap on
   the sign-in field, the pricing selects, and the marketplace sort jumped the
   page and left it zoomed. The controls keep their own lettering everywhere
   else; at touch widths the text steps up to the floor and stops fighting the
   browser. */
@media (max-width: 860px) {
  /* The [class] variants exist only to out-specify the per-control rules above
     (.fs .filter-sort is 0-2-0; .fs select is 0-1-1 and loses). Same declaration,
     enough weight to actually apply. */
  .fs input, .fs select, .fs textarea,
  .fs input[class], .fs select[class], .fs textarea[class],
  .fs [class] input, .fs [class] select, .fs [class] textarea {
    font-size: 16px;
  }
}

/* ── Last twelve off-ladder roles ────────────────────────────────────────────
   These twelve still took their size, weight or tracking from styles.css, which
   is why the measured system had a tail of 14.4 / 14.72 / 15.2 / 20.8px and
   weights of 650 / 850 / 900. Named here so the ladder above is the whole
   system and nothing renders at a height that is not one of its ten. */

/* Pricing FAQ: the question reads at spec size, the answer one step below it. */
.fs .faq-item summary { font-size: var(--t-body); letter-spacing: var(--tr-callout); }
.fs .faq-item p       { font-size: var(--t-small); }

/* Estimator field labels and readouts — title-block fields and their numerals. */
.fs .calc-field-header label { font-size: var(--t-letter); font-weight: var(--w-letter); letter-spacing: var(--tr-letter); }
.fs .calc-val                { font-size: var(--t-small); }
.fs .calc-total-row > span   { font-size: var(--t-small); font-weight: var(--w-strong); }
.fs .calc-total-num          { letter-spacing: var(--tr-heading); }

/* Weights that named a face the sheet does not load. */
.fs .fs-state-tag b     { font-weight: var(--w-display); }
.fs .upload-zone small  { font-weight: var(--w-letter); }
.fs .mk-type-inner strong { font-size: var(--t-callout); font-weight: var(--w-strong); letter-spacing: var(--tr-letter); }

.fs .dash-tab-intro p { font-size: var(--t-small); }
.fs .auth-modal h2    { font-size: var(--t-h3); }
.fs .mk-rate-suffix   { font-size: var(--t-small); }

/* letter-spacing in em resolves against the declaring element's font-size and
   then inherits as a fixed length, so a child at a different size drifts off
   the regime (0.14em on an 11.5px parent reaches a 13.1px child as 0.123em).
   Where a child sets its own size, it restates its own tracking. */
.fs .job-meta span {
  font-size: var(--t-letter);
  font-weight: var(--w-letter);
  letter-spacing: var(--tr-letter);
}
.fs .calc-total-row > span { letter-spacing: var(--tr-callout); }

/* ════════════════════════════════════════════════════════════════════════════
   ONE BORDER
   A figure sheet is ruled to a single border, and everything drawn on it
   registers to that border. Measured at 1440px this sheet had ELEVEN left
   rails — 0, 26, 29, 90, 107, 117, 122, 136, 172, 290, 340 — because the
   pages carried over from styles.css lay out on `--max: 1180px` with a 1rem
   gutter (rail 130) while the sheet field is `--sheet-max: 1260px` with
   `--gut` (rail 90), and several containers were clamped tighter still by a
   `max-width: 760px / 860px` that quietly beat the `width` override already
   written here. The rail is now one expression, used everywhere.
   ═════════════════════════════════════════════════════════════════════════ */

.fs { --rail: max(var(--gut), calc((100% - var(--sheet-max)) / 2)); }

/* Bands that were laid out on the old container. `max-width: none` is the
   operative declaration: the widths below were already correct and losing. */
.fs .page-hero,
.fs .create-hero,
.fs .section,
.fs .faq-hero,
.fs .faq-body,
.fs .maker-onboard,
.fs .dashboard-section,
.fs .faq-strip,
.fs .calc-section {
  width: min(var(--sheet-max), calc(100% - var(--gut) * 2));
  max-width: none;
  margin-inline: auto;
  padding-inline: 0;
}

/* A hero's children inherited `margin-inline: auto`, so every h1 carrying a
   measure cap in ch (14ch on the dashboard, 15ch on makers and about) was
   centred in the field: the headline started at x=430 with 340px of blank
   sheet to its left while its own eyebrow started at 172. A heading starts at
   the border. */
.fs .page-hero > *,
.fs .create-hero > * { margin-inline: 0; }

/* The maker registration form keeps a form's measure, but sits on the border
   under its heading instead of floating centred in the field. */
.fs .maker-form { max-width: 760px; }

/* Title block, top and bottom.

   The header stays FULL BLEED — a border block on a drawing runs to the sheet
   edge, and the blue action reads as the anchor of the whole bar. Padding the
   header in stranded it: 90px of white at both ends and the action floating as
   a rectangle in the middle of nothing.

   The brand still registers to the rail, via a rail-width TRACK rather than
   padding. A percentage inside a grid item resolves against that item's own
   track, which for an `auto` track is circular and silently falls back to the
   gutter (it put the brand at x=42, not 90); a percentage in
   `grid-template-columns` resolves against the grid container's content box,
   which is the body width and is definite. */
.fs .site-header { padding-inline: 0; }
/* On a phone there is no rail track, so the brand carries the rail itself. */
.fs .brand { padding-inline: var(--gut) var(--d3); }

/* Desktop only. The phone header is a two-row grid-template-areas layout
   further up this file, and an unscoped `grid-template-columns` here beats it
   on source order: five tracks against three named areas put SIGN IN straight
   on top of the wordmark. */
@media (min-width: 981px) {
  /* rail | brand | index (+ the block's blank notes cell) | auth | action */
  .fs .site-header { grid-template-columns: var(--rail) max-content 1fr max-content max-content; }
  .fs .site-header > .brand { grid-column: 2; padding-left: 0; }
  /* The two right-hand cells carry the page's only two actions and are the
     widest lettering in the block; they get the module, not the half-module. */
  .fs .nav-auth,
  .fs .nav-cta { padding-inline: var(--d3); }
}

/* The footer has no bleeding block to anchor it, so it takes the rail as
   padding: wordmark on the left border, the index running to the right one. */
.fs .site-footer { padding-inline: var(--rail); grid-template-columns: auto 1fr; }

/* makers.html drops a .proof-band inside a negative sheet that already
   supplies the ground; the band's own 32px inset pushed its heading off the
   rail, and its 80px bottom margin left a slab of empty black above the
   footer. The sheet spaces the band. */
.fs .fs-negative .proof-band { padding-inline: 0; margin-bottom: 0; }
.fs .site-footer .footer-wordmark { margin-inline: 0 var(--d3); }
.fs .fs-footer-links { justify-content: flex-end; }
.fs .site-footer a:last-child { padding-right: 0; }

/* The printed grid does not change with the viewport, so neither do the rungs.
   The top three step down one rung at touch widths: 45px of horizontal inset
   on a 390px screen is twelve percent of the sheet, and at 90px a single band
   would take a third of the viewport's height. Every value is still a whole
   number of modules. */
@media (max-width: 860px) {
  .fs { --d4: 30px; --d5: 45px; --d6: 60px; }
}

/* ── The tail ────────────────────────────────────────────────────────────────
   Thirty-one values still reached the page from styles.css, on elements the
   sheet had never restated. Most are em-based, so they also drifted with the
   font-size of whatever they sat on: `.job-meta span` alone accounted for 324
   of them at 6.72px and 8.64px. Named here, on the rung. */
.fs .job-meta span            { padding: var(--d1) var(--d2); }
.fs .job-meta,
.fs .job-view-btn             { margin-top: var(--d2); }
.fs .mk-field,
.fs .calc-field,
.fs .compute-options label,
.fs .mk-type-inner,
.fs .bid-field,
.fs .auth-field,
.fs .panel-title,
.fs .detail-header-left       { gap: var(--d1); }
.fs .mk-check                 { padding: 0; }   /* the bordered <span> is the chip */
.fs .mk-fieldset              { gap: var(--d2); }
.fs .q-selects                { margin-bottom: var(--d2); gap: var(--d1); }
.fs .worker-actions           { gap: var(--d2); }
.fs .upload-zone small        { margin-top: var(--d1); }
.fs .upload-glyph             { margin-bottom: var(--d2); }
.fs .detail-meta-item span    { margin-bottom: var(--d1); }
.fs .bid-form .button-primary { margin-top: var(--d2); }
.fs .auth-close               { padding: var(--d1); }
.fs .detail-close             { padding: var(--d1); }
.fs .pb-toast,
.fs .detail-header            { padding: var(--d2); }
.fs .dash-loading             { padding: var(--d4) 0; }
.fs .marketplace-section      { padding-block: var(--d4); }
.fs .studio-layout            { margin-bottom: var(--d5); }
.fs .proof-band               { padding-block: var(--d4); }
.fs .calc-inputs              { gap: var(--d2); }
.fs .fs-figno                 { margin-bottom: var(--d2); }
.fs input, .fs select, .fs textarea { margin-block: 0; }
.fs .upload-zone,
.fs .compute-options,
.fs .job-status,
.fs .quote-total,
.fs .fs-party .fs-figno       { margin-bottom: var(--d2); }
.fs .marketplace-section,
.fs .marketplace-section.fs-inner { padding-block: var(--d4); }
.fs .proof-band.fs-inner      { padding-block: var(--d4); }

/* The carried-over hero centred itself inside `min-height: 540px`. On a title
   sheet that air is the composition; on a three-line dashboard or marketplace
   header it was 250px of empty stock above and below the only sentence there.
   The rungs space the band; the band is as tall as what it says. */
.fs .page-hero { min-height: 0; align-content: start; }

/* The filter rail's divider is a vertical rule between two groups of pills.
   Once the pills wrap it lands at the head of a row, dividing nothing. */
@media (max-width: 860px) {
  .fs .filter-divider { display: none; }
}

/* Last six. Inline styles and a handful of un-restated rules from styles.css. */
.fs .fs-band                  { padding-block: var(--d5); }
.fs .signal-label             { margin-bottom: var(--d2); }
.fs input, .fs select, .fs textarea { padding-inline: var(--d2); }
.fs .calc-total-row           { padding-bottom: var(--d2); }
.fs .detail-header            { gap: var(--d2); }
.fs .bid-form .button-primary,
.fs .detail-panel .button-primary { margin-top: var(--d2); }
.fs h2                        { margin-bottom: var(--d2); }
.fs .fs-figno                 { margin-bottom: var(--d2); }

/* The index sat left in a 1fr cell and left a 418px hole at sheet width, with
   the rule after ABOUT hanging in the middle of it. A title block's cells
   divide the whole block; they do not stop halfway. Each link takes an equal
   share of the slack, so the ruling reaches the actions. */
@media (min-width: 981px) {
  .fs .nav-links a { flex: 1 1 auto; justify-content: center; }
}


/* ── Title block, cut to height ──────────────────────────────────────────────
   The bar ran 72px on 11.5px lettering, because every cell padded itself a
   half-module top and bottom and then the row stretched to the tallest. An
   index cell came out 98x72 around one short word, and the block read as
   furniture sitting on the sheet rather than as the sheet's own title block —
   which is ruled tight to its fields.

   The bar is now one number: the wordmark plus a half-module of clearance
   above and below it. Cells stretch to that and centre their lettering in it
   instead of setting the height themselves.

   ponytail: one height token and a padding-block reset, not a header rewrite. */
.fs .site-header { min-height: var(--bar); }
.fs { --bar: 52px; }
.fs .brand-logo { height: 22px; }

@media (min-width: 981px) {
  .fs .nav-links a,
  .fs .nav-auth,
  .fs .nav-cta,
  .fs .nav-user-chip { padding-block: 0; }
}

/* The signed-in chip. styles.css:2451 capped the username at 120px and
   ellipsised it at the ninth character — the one field in the whole block that
   names the person reading it, and the one the cap was hiding. The name is now
   the account link itself; a separate MY ACCOUNT cell was 118px of the bar
   restating where the name already goes. Chip drops 320px -> ~190px, and the
   name fits. */
.fs .nav-user-label { max-width: none; }
.fs .nav-user-chip { gap: var(--d3); }
@media (min-width: 981px) {
  .fs .nav-user-chip { padding-inline: var(--d3); }
}

/* Under 1180 the block cannot hold six index cells, the identity and a
   full-bleed action at once — the index needs 486px at its tightest and got
   352, so PRICING and ABOUT ran under the chip. The action is the cell that
   goes: CREATE in the index is the same destination, and every page opens on
   its own primary action. Above 1180 everything is back. */
@media (max-width: 1179px) {
  .fs .nav-cta { display: none; }
}

/* On the phone bar the chip shares one row with the wordmark and MENU, so it
   takes the half-module. styles.css:1333 hid the name outright below 720 —
   which now removes the only account link there, not a decoration. It stays,
   with a cap, and the full address is on the element's title. */
@media (max-width: 980px) {
  .fs .nav-user-chip { gap: var(--d2); padding-inline: var(--d2); min-width: 0; }
  .fs .nav-user-label {
    display: block;
    max-width: none;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* On a 390px bar the name genuinely cannot fit whole beside SIGN OUT and MENU.
   Rather than pick a cap and hope, the chip takes the row's slack and the name
   ellipsises to exactly what is left — no magic number to re-tune when the
   wordmark or the lettering changes. */
@media (max-width: 560px) {
  .fs .site-header { grid-template-columns: auto minmax(0, 1fr) auto; }
  .fs .nav-user-chip { justify-content: flex-end; }
}

/* Everything that clears the bar was measured against the old 72px one: the
   drop-down index opened 22px below the rule it hangs from, and the three
   sticky panels parked 21-40px under a bar that is no longer there. They read
   the bar's height now, so the next time it moves they move with it. */
.fs .nav-links { top: var(--bar); }
.fs .control-panel,
.fs .quote-panel,
.fs .calc-breakdown,
.fs .fs-plate-stack { top: calc(var(--bar) + var(--d2)); }

/* ── Groups that stopped reading as groups ───────────────────────────────────
   A range input is 44px tall so it can be tapped, but the track it draws is
   2px in the middle of that. The other 42px is invisible, and the ladder then
   spaced AROUND it: on the estimator the label sat 40px off its own slider,
   the tick scale 48px under it, and the next field's label 43px after that —
   four evenly spaced lines with no grouping at all. Collapsing the hit area's
   own box makes the authored gap the gap you see. The 44px target is not
   touched; only its margin is. */
.fs input[type="range"] { margin-block: -14px; }

/* …and once the slider stops inflating its group, the group separations have
   to out-rank what is inside them. One module against a third. */
.fs .range-grid    { gap: var(--d3); }
.fs .calc-field    { margin-bottom: var(--d3); }

/* The estimator's two panels overran the sheet by 17px on a 390px screen: a
   grid item's automatic minimum size is its content, so the selects inside
   refused to shrink and pushed the panels past the rail. A module of inset on
   each side of a 358px panel is also too much of it. */
@media (max-width: 860px) {
  .fs .calc-layout > * { min-width: 0; }
  .fs .calc-inputs,
  .fs .calc-breakdown { padding: var(--d2); }
}
