/* =========================================================================
   Omega Lithograph — theme  ·  "INK STROKE"
   =========================================================================
   THE CONCEPT, in one line: the identity is a brush stroke of magenta ink
   swept across a black omega, and the site is built out of that.

   Their logo is the brief. A black Ω, a magenta brush stroke dragged through
   it with dry-brush texture where the ink runs out, then OMEGA and a
   letterspaced LITHOGRAPH INC underneath. Three things come straight off it
   and nothing else is invented:

     1. THE INK.   #A8006C is sampled from the artwork, not chosen. It is the
                   accent everywhere. Cyan #0F6FB8 is demoted to a supporting
                   role and appears only where the subject is genuinely
                   four-color process. There is no yellow, and no rainbow.
     2. THE STROKE. assets/brand/stroke.svg is that same sweep, traced out of
                   the logo into real curves. It is NOT drawn anywhere on this
                   site — see the note above the header section for why. The
                   brush reaches every page inside the logo artwork instead.
     3. THE BLACK. The omega is drawn in near-black, so the page is too, and
                   whole sections are set in it. See THE BANDS below.

   TYPE. Big Shoulders Display 700/800 for headlines — condensed, industrial,
   drawn for signage, and it rhymes with the narrow angular OMEGA in the
   wordmark. Instrument Sans 400/500/600 for text. DM Mono 400/500 for
   eyebrows, figures and the equipment lists, so a list of presses reads like
   the job ticket it is. Big Shoulders is condensed, which means it has to be
   set BIG to pay for itself: the display scale here is roughly 40% larger
   than a normal-width face would take, at the same column width.

   THE BANDS — this is the contrast fix, and it is the most important thing in
   the file. v1 put the whole site on one paper ground and the page read flat.
   Now every page alternates three grounds down its length:

     --paper  #F4F1EC   warm stock, the default
     --white  #FFFFFF   the fresh sheet
     --ink-band #121317 near-black, type knocked out

   Sections alternate paper -> white by default (a zero-specificity rule keyed
   off nth-of-type, so nothing has to be class-tagged for the rhythm to work),
   and .band / .band--white / .band--ink override it wherever a page wants to
   place a ground by hand. Two dark bands are guaranteed on EVERY page type
   without a copy module lifting a finger: .page-hero and the closing .cta,
   plus the footer, which is the deepest ground on the site.

   INSIDE A DARK BAND EVERYTHING INVERTS. Not the type only — the rules, the
   card grounds, the tag wells, the button fills, the form controls, the FAQ
   accordions, the eyebrow color, the focus ring, the ink stroke itself. That
   is done by rebinding a small set of surface tokens on the band rather than
   by writing a second rule for every component: components only ever name
   --ground / --surface / --tx / --line / --accent, so a half-inverted band is
   not something this file can express. Fix the ground, not each thing
   standing on it.

   CONTRAST. Every text/ground pair is computed, not eyeballed, and the ratio
   is recorded beside the token. Body text clears 4.5:1 and large text 3:1 on
   BOTH the light bands and the ink bands. Solid buttons clear 4.5:1 on their
   label and 3:1 on their own edge against whichever ground they sit on, which
   is why the button fill is a separate token from the accent text color and
   is brightened inside a dark band.

   RESTRAINT. No gradients as decoration, no glassmorphism, no shadow heavier
   than a hairline (one exception, the floating nav dropdown, noted where it
   is). Corners stay near-square: a printed piece is trimmed, not rounded.

   Contract with the shared assets/site.js — do not rename:
     .reveal -> .reveal.in       scroll reveal (a genuine no-op under
                                 prefers-reduced-motion)
     nav.nav-menu-open           mobile menu
     .dropdown.open              nav dropdowns
     .site-header.scrolled       set past 12px of scroll
     .form-status.ok / .err      shared contact-form status element

   .foot-giant is gone. FOOTER_GIANT is False in the profile, the engine no
   longer emits the element, and its rules are deleted rather than left here
   as dead weight.
   ====================================================================== */

:root {
  /* --- Stock -----------------------------------------------------------
     Warm neutrals, biased a few degrees toward the magenta so they read as
     chosen rather than inherited. There is no #808080 anywhere in this file. */
  --paper:    #F4F1EC;   /* the default ground */
  --white:    #FFFFFF;   /* the fresh sheet — a full band, and card stock */
  --paper-2:  #EDE8DF;   /* a shade deeper: tag wells, insets, progress track */

  /* --- Ink ------------------------------------------------------------
     --ink is deeper than v1's #14171C, because "not enough contrast" was the
     complaint. Measured against paper / white / paper-2:
       --ink    17.37 : 19.57 : 16.04
       --ink-2   8.15 :  9.18 :  7.52
       --ink-3   5.96 :  6.71 :  5.50   (floor — never lighter than this for type) */
  --ink:      #0B0C0E;
  --ink-2:    #4D4649;
  --ink-3:    #615A5D;
  --ink-band: #121317;   /* the dark band ground */

  /* --- The ink, sampled ------------------------------------------------
     #A8006C is the ink lifted off the brush stroke in their own artwork, and
     it survives untouched in the LOGO — that artwork is theirs and is never
     recolored. The interface accent is a step darker and a step toward violet,
     which reads as deliberate beside the mark rather than competing with it.
       --accent      #5C1150   12.09 paper : 12.72 white-on : 10.89 paper-2
       --accent-dn   #400B38   hover / pressed, darker again
       --accent-hi   #7A1A68   ornament and dark-band fills, not light-ground text
       --accent-lt   #C07FB4    6.25 on the ink band — the on-dark text accent
     --cyan is supporting only: four-color-process subjects and the press
     control strip on a card head. 4.68 on paper, 5.27 on white. It is under
     the floor on --paper-2, so it is never set as text there. */
  --accent:      #5C1150;
  --accent-dn:   #400B38;
  --accent-hi:   #7A1A68;
  --accent-lt:   #C07FB4;   /* the accent as text on a dark ground */
  --accent-soft: rgba(92, 17, 80, .085);
  --ink-magenta: #A8006C;   /* the logo's own ink. Reference only — do not
                               restyle the artwork with it. */
  --cyan:        #0F6FB8;

  /* --- Semantic surface tokens ----------------------------------------
     EVERY component below names these and never a raw hex. .band--ink
     rebinds the whole set in one place, which is what makes the inversion
     complete instead of half done. */
  --ground:    var(--paper);   /* the band's own ground */
  --surface:   var(--white);   /* a card standing on that ground */
  --surface-2: var(--paper-2); /* a well or a tag inside a card */
  --tx:        var(--ink);     /* primary type */
  --tx-2:      var(--ink-2);   /* secondary type */
  --tx-3:      var(--ink-3);   /* muted type, mono labels */

  /* Hairlines are ink at low alpha, never white at low alpha — on paper a
     white rule is invisible, which is exactly how an inverted theme ships
     broken. --rule-strong is the floor for a CONTROL boundary (input, select,
     ghost button, drop zone): those clear 3:1 on their surface, and a 13%
     hairline does not. */
  --line:        rgba(11, 12, 14, .14);
  --line-2:      rgba(11, 12, 14, .26);
  --line-3:      rgba(11, 12, 14, .38);   /* trim and crop marks */
  --rule-strong: rgba(11, 12, 14, .55);   /* 4.22:1 on white — form controls */

  /* Solid buttons. Deliberately NOT var(--accent): a button has to clear
     4.5:1 on its label AND 3:1 on its own edge against the ground behind it,
     and the accent that does that on paper is too dark on near-black. The
     dark-band values are set on .band--ink further down.
       light  #A8006C  label 7.29  edge 6.47 paper / 7.29 white
       hover  #8A0059  label 9.44  edge 8.38 / 9.44 */
  --btn-bg:    var(--accent);
  --btn-bg-hi: var(--accent-dn);
  --btn-fg:    #FFFFFF;

  /* The focus ring sits at outline-offset, i.e. on the GROUND behind the
     control, not on the control — so ink on paper is 17.37:1 and paper on the
     ink band is 16.48:1. Rebound on dark bands. */
  --focus: var(--ink);

  /* --- Type ------------------------------------------------------------
     Every stack carries a real fallback. Big Shoulders is condensed, so its
     fallback has to be condensed too or the masthead reflows a third wider
     during the font swap — which is also why the nav breakpoint has slack. */
  --display: "Big Shoulders Display", "Archivo Narrow", "Arial Narrow",
             "Helvetica Neue Condensed", ui-sans-serif, system-ui, sans-serif;
  --body:    "Instrument Sans", ui-sans-serif, system-ui, -apple-system,
             "Segoe UI", Helvetica, Arial, sans-serif;
  --mono:    "DM Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
             "Liberation Mono", monospace;

  /* Corners stay close to square. A printed piece is trimmed, not rounded. */
  --r-card: 3px;
  --r-cta:  2px;
  --r-pill: 999px;

  --wrap:   1180px;
  --head-h: 74px;         /* shared by the sticky header and the mobile menu inset */
  --ease:   cubic-bezier(.22,.61,.36,1);

  /* --- Aliases ---------------------------------------------------------
     Names the engine and the profile reach for by hand. .btn--moss is emitted
     by cta_block() and by every hero; --stone-900, --brass and --r appear in
     inline styles on page types Omega does not build. Remapped rather than
     deleted so nothing resolves to an empty string if a copy module reuses
     one. --paper is itself such an alias: build.py writes
     style="color:var(--paper)" on the footer brand word. */
  --moss:       var(--accent);
  --moss-deep:  var(--accent-dn);
  --brass:      var(--accent-hi);
  --brass-soft: var(--accent-soft);
  --stone-900:  var(--paper-2);
  --r:          var(--r-card);
  --mag:        var(--accent);      /* v1 token name, still on a few inline styles */
  --mag-soft:   var(--accent-soft);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--tx);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { max-width: 100%; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 {
  font-family: var(--display); font-weight: 700;
  letter-spacing: -.012em; line-height: .94; margin: 0;
  color: var(--tx);
}
p { margin: 0 0 1em; }
ul { margin: 0 0 1em; padding-left: 1.15em; }
::selection { background: var(--btn-bg); color: var(--btn-fg); }

.wrap { width: min(100% - 40px, var(--wrap)); margin-inline: auto; }

/* =======================================================================
   THE BANDS
   =======================================================================
   1. The default rhythm. Zero specificity on purpose (:where wraps the whole
      compound, so :nth-of-type contributes nothing) — a copy module that
      tags a section with .band--ink or .band--white always wins, and one that
      tags nothing still gets an alternating page. Sections are the only
      direct children main ever has, so nth-of-type is counting exactly the
      thing it looks like it is counting.
   2. .band / .band--white / .band--ink, placed by hand.
   3. The engine-emitted bands that are dark on every page type, so the
      alternation does not depend on a copy module at all: the interior page
      hero, the closing CTA, and the footer.

   Order matters here and is deliberate: the dark block is LAST, so
   class="section band band--ink" resolves dark. The one combination this
   cannot serve is a .page-hero explicitly marked .band--white; nothing writes
   that, and if something ever does, add it to the light block below.
   ==================================================================== */

/* 1 — default alternation. A white band flips the card stock to paper and the
   tag wells one shade deeper again, because a white card on a white band is a
   card you cannot see. Measured on --surface #F4F1EC / --surface-2 #E6E0D6:
   --tx 17.37 : 14.91, --tx-2 8.15 : 6.99, --tx-3 5.96 : 5.11,
   --accent 6.47 : 5.55. */
:where(main > section:nth-of-type(even)) {
  background: var(--white);
  --ground: var(--white); --surface: var(--paper); --surface-2: #E6E0D6;
}
:where(main > section:nth-of-type(odd)) {
  background: var(--paper);
  --ground: var(--paper); --surface: var(--white); --surface-2: var(--paper-2);
}

/* 2 — placed by hand */
.band  { background: var(--ground); color: var(--tx); }
.band, .band--white {
  --ground: var(--paper); --surface: var(--white); --surface-2: var(--paper-2);
  --tx: var(--ink); --tx-2: var(--ink-2); --tx-3: var(--ink-3);
  --line: rgba(11, 12, 14, .14); --line-2: rgba(11, 12, 14, .26);
  --line-3: rgba(11, 12, 14, .38); --rule-strong: rgba(11, 12, 14, .55);
  --accent: #5C1150; --accent-hover: var(--accent-dn);
  --btn-bg: #5C1150; --btn-bg-hi: #400B38;
  --cyan: #0F6FB8; --focus: var(--ink);
}
/* A white band's cards need to be something other than another white card, so
   the card stock steps DOWN to paper rather than the whole scheme inverting. */
.band--white {
  --ground: var(--white); background: var(--white); color: var(--tx);
  --surface: var(--paper); --surface-2: #E6E0D6;
}

/* 3 — the dark ground, and the complete inversion that goes with it.
   Measured on --ink-band #121317 / --surface #1A1C21 / --surface-2 #22242A:
     --tx   (paper)   16.48 : 15.13 : 13.42
     --tx-2 #C3BABF    9.81 :  9.01 :  8.20
     --tx-3 #ADA3A9    7.59 :  6.97 :  6.34
     --accent #C07FB4  6.25 :  5.74 :  5.22   (clears 4.5:1 on all three)
     --btn-bg #8A3A7C  label 5.62 on white; edge 2.71 on the band, so the
                       button also carries a --line-2 border to hold its shape
     --btn-bg-hi #A34F92 label 4.61 on white
   .site-footer is a step deeper again (--ink #0B0C0E) so the page closes on
   the blackest ground it owns; every ratio above only improves there. */
.band--ink, .page-hero, .section--hero-sub, .cta, .site-footer {
  --ground:    var(--ink-band);
  --surface:   #1A1C21;
  --surface-2: #22242A;
  --tx:        var(--paper);
  --tx-2:      #C3BABF;
  --tx-3:      #ADA3A9;
  --line:        rgba(244, 241, 236, .14);
  --line-2:      rgba(244, 241, 236, .26);
  --line-3:      rgba(244, 241, 236, .38);
  --rule-strong: rgba(244, 241, 236, .55);
  --accent:      var(--accent-lt);
  --accent-hover:#D6A0CB;
  --accent-soft: rgba(192, 127, 180, .14);
  --btn-bg:      #8A3A7C;
  --btn-bg-hi:   #A34F92;
  --cyan:        #5AA8E0;
  --focus:       var(--paper);
  --stone-900:   var(--surface-2);
  background: var(--ground);
  color: var(--tx);
}
.site-footer { --ground: var(--ink); }

/* Light bands need --accent-hover too; it is only named separately above so
   the dark block can move it in the same sweep. */
:root { --accent-hover: var(--accent-dn); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--btn-bg); color: var(--btn-fg); padding: 12px 18px;
  border-radius: 0 0 var(--r-cta) 0; font-weight: 600;
}
.skip-link:focus { left: 0; }

/* Focus. The ring is at an offset, so it lands on the ground behind the
   control: ink on paper 17.37:1, paper on the ink band 16.48:1. Every
   interactive element in the file resolves to this unless it says otherwise,
   and the ones that need a different offset say so at their own rule. */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 2px; }
a:focus-visible, button:focus-visible, summary:focus-visible,
label:focus-visible, [tabindex]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px;
}

/* =========================================================== the ink stroke */
/* The brush stroke is deliberately NOT drawn anywhere on this site.

   It was used three ways and all three were rejected: as a swept underline
   beneath headings it read as a highlighter and had multiplied to three per
   page; on a dark band it inherited --accent (a color picked so accent TEXT
   clears 4.5:1 on near-black) and came out pale lilac; and as a section
   divider it was simply still the brush.

   assets/brand/stroke.svg stays in the repo — it is a real deliverable, a
   traced vector of their mark that they did not previously own, and it belongs
   in their brand kit. The mark still appears on every page inside the LOGO
   artwork itself, which is where it came from and where it works.

   If it is ever reintroduced: once per page at most, never under type, and
   paper-on-ink rather than a tinted accent on dark grounds. */

/* ---------------------------------------------------------------- header */
/* Solid paper, and deliberately NOT a translucent blurred bar. Two reasons: a
   printed sheet is opaque, so type ghosting through the masthead is wrong
   here; and backdrop-filter makes an element the containing block for every
   position:fixed descendant — which silently breaks the mobile menu panel and
   the menu's pinned CTA, both of which are fixed children of this header. */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  transition: border-color .2s var(--ease);
}
/* site.js sets .scrolled past 12px. The sheet has lifted off the table by a
   hairline — that is the whole effect. */
.site-header.scrolled { border-bottom-color: var(--line-2); }

.nav { display: flex; align-items: center; gap: 26px; height: var(--head-h); }

/* --------------------------------------------------------- the logo lockup */
/* MARK is now an <img> of their real artwork, and BRAND_HTML is an empty
   string — so .brand holds the image and an empty <span> that build.py has
   already written an inline color onto. Hide the span; an inline style cannot
   be beaten by a color rule but it can be beaten by not rendering the box.
   .brand b is kept for the same reason the aliases above are: the engine can
   emit it and this file should not be the reason it disappears. */
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--display); font-weight: 700; font-size: 1.15rem;
  letter-spacing: -.012em; white-space: nowrap; color: var(--tx);
  min-width: 0;
}
.brand span:empty { display: none; }
.brand b { font-weight: 700; color: var(--accent); }

/* The artwork is 552x210 (2.63:1) with a transparent ground and BLACK
   letterforms. 114px wide puts it at 43px tall in a 74px bar, which is the
   size at which the letterspaced LITHOGRAPH INC under the wordmark is still
   readable rather than a gray smear. Never set a height: the intrinsic
   width/height attributes reserve the box, and height:auto keeps the ratio. */
.brand-logo {
  display: block; width: 114px; height: auto; flex: none;
}
/* On any near-black ground the black omega and the black OMEGA would vanish
   and only the magenta stroke would survive — a broken logo, not a clever
   one. Inverting it is worse: it would take the magenta with it. So on dark
   the lockup gets a paper swatch, which is what a printer would do anyway. */
.band--ink .brand-logo, .site-footer .brand-logo, .cta .brand-logo,
.page-hero .brand-logo, .section--hero-sub .brand-logo {
  background: var(--paper);
  padding: 9px 13px;
  border-radius: var(--r-cta);
}
.site-footer .brand-logo { width: 152px; padding: 11px 15px; }

/* .mark is the engine's inline-SVG mark slot. Omega ships an <img> instead, so
   this never renders today — kept sized so swapping MARK back to an SVG is a
   profile edit rather than a stylesheet edit. */
.mark { width: 26px; height: 30px; flex: none; }

.nav-links { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.nav-links > a, .drop-trigger {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 12px; border-radius: var(--r-cta);
  font-size: .92rem; font-weight: 500; color: var(--ink-2);
  background: none; border: 0; cursor: pointer; font-family: var(--body);
  transition: color .18s var(--ease), background .18s var(--ease), box-shadow .18s var(--ease);
}
.nav-links > a:hover, .drop-trigger:hover { color: var(--ink); background: rgba(11, 12, 14, .05); }
/* Current page gets a 2px rule under the word rather than a filled pill — the
   underscore a proofreader would put there. */
.nav-links > a[aria-current], .drop-trigger[aria-current] {
  color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent);
}
.drop-caret { font-size: .6rem; color: var(--ink-3); }

.has-dropdown { position: relative; }
.dropdown {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 60;
  min-width: 272px; padding: 7px;
  background: var(--white); border: 1px solid var(--line-2);
  border-radius: var(--r-card);
  /* The one shadow in the file. A floating menu has to separate from the page
     under it; a hairline border alone cannot do that. Faint and ink-tinted. */
  box-shadow: 0 12px 30px rgba(11, 12, 14, .12);
  opacity: 0; visibility: hidden; transform: translateY(-5px);
  transition: opacity .18s var(--ease), transform .18s var(--ease), visibility .18s;
}
.has-dropdown:hover .dropdown,
.has-dropdown:focus-within .dropdown,
.dropdown.open { opacity: 1; visibility: visible; transform: none; }
.dropdown a { display: block; padding: 9px 12px; border-radius: var(--r-cta); transition: background .16s var(--ease); }
.dropdown a:hover { background: var(--accent-soft); }
.dropdown b { display: block; font-family: var(--display); font-size: 1.05rem; font-weight: 700; color: var(--ink); }
.dropdown span { display: block; font-size: .8rem; color: var(--ink-3); margin-top: 2px; }
.dropdown--mega { min-width: 272px; }
.drop-all { border-bottom: 1px solid var(--line); border-radius: var(--r-cta) var(--r-cta) 0 0 !important; margin-bottom: 5px; padding-bottom: 11px !important; }
.drop-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 2px; }
.drop-col { min-width: 0; }
/* One county means one column; the engine still emits the second div. */
.drop-col:empty { display: none; }
.drop-county {
  margin: 9px 0 2px; padding: 0 12px;
  font-family: var(--mono); font-size: .64rem; letter-spacing: .13em;
  text-transform: uppercase; color: var(--accent);
}

.nav-cta { display: flex; align-items: center; gap: 10px; }
.burger {
  display: none; width: 42px; height: 38px; padding: 10px 9px; cursor: pointer;
  background: none; border: 1px solid var(--rule-strong); border-radius: var(--r-cta);
}
.burger span { display: block; height: 2px; background: var(--ink); border-radius: 2px; margin: 3px 0; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 22px; border-radius: var(--r-cta);
  font-family: var(--body); font-size: .92rem; font-weight: 600;
  background: var(--btn-bg); color: var(--btn-fg); border: 1px solid var(--btn-bg);
  cursor: pointer; white-space: nowrap;
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.btn:hover { background: var(--btn-bg-hi); border-color: var(--btn-bg-hi); color: var(--btn-fg); }
/* Alias kept because cta_block() and every hero emit it by name. */
.btn--moss { background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.btn--moss:hover { background: var(--btn-bg-hi); border-color: var(--btn-bg-hi); }
/* The outlined variant takes the band's own type color, so it flips with the
   ground for free. Its edge is --rule-strong, which is the 3:1 floor. */
.btn--ghost { background: transparent; color: var(--tx); border-color: var(--rule-strong); }
.btn--ghost:hover { background: transparent; color: var(--accent-hover); border-color: var(--accent); }
.btn--lg { padding: 15px 28px; font-size: 1rem; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }
.arrow { font-size: .85em; }
.link-arrow { color: var(--accent); font-weight: 500; }
.link-arrow:hover { color: var(--accent-hover); text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------- eyebrow */
/* Press-ticket register: DM Mono, letterspaced, preceded by a short leader
   rule the way a callout on a spec drawing is. No pill, no status dot. The
   color is var(--accent), which the dark block has already re-pointed at
   #E85AAE — that is the whole eyebrow inversion. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono); font-size: .69rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--accent);
}
.eyebrow::before { content: ""; width: 22px; height: 1px; background: var(--accent); flex: none; }
/* service_page() and cta_block() emit .hero-eyebrow alongside .eyebrow; it is
   a positioning hook rather than a restyle. */
.hero-eyebrow { display: inline-flex; }

/* ------------------------------------------------------- press furniture */
/* .marks — a trim-line hairline broken by a registration target, with a tick
   turned up at each end. Quiet section furniture: one between two blocks that
   need separating, never more than a couple to a page. Renders from an empty
   <div class="marks" aria-hidden="true"></div>.
   --marks-ground has to match whatever it sits on, because the target knocks a
   hole in the rule — so it is pinned to --ground and follows the band. */
.marks {
  position: relative; height: 24px; margin: 0;
  --marks-ground: var(--ground);
  border-left: 1px solid var(--line-3);
  border-right: 1px solid var(--line-3);
}
.marks::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; background: var(--line-2);
}
.marks::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 13px; height: 13px; transform: translate(-50%, -50%);
  border: 1px solid var(--line-3); border-radius: 50%;
  /* the center dot is the ink itself */
  background: var(--marks-ground) radial-gradient(circle at 50% 50%, var(--accent) 0 1.6px, transparent 1.7px);
  box-shadow: 0 0 0 4px var(--marks-ground);
}
.card .marks, .svc .marks, .prod .marks, .spec .marks,
.aside-card .marks, .contact-card .marks, .city-card .marks { --marks-ground: var(--surface); }
/* A band-level .marks is a SIBLING of .wrap, not a child of it, so without
   this its end ticks land on the viewport edge instead of on the trim line. */
.hero > .marks, .page-hero > .marks, .section--hero-sub > .marks,
.cta > .marks, .site-footer > .marks, .band > .marks {
  width: min(100% - 40px, var(--wrap)); margin-inline: auto;
}

/* Crop marks at the four corners of a hero band: two arms that stop short of
   the corner, the way a trimmed sheet is marked. Eight 1px gradients, so it
   costs no markup and no request. --line-3 follows the band, so they are ink
   on paper and paper on ink without a second rule. */
.hero::after, .page-hero::after, .section--hero-sub::after {
  content: ""; position: absolute; inset: 16px; pointer-events: none;
  --arm: 20px; --gap: 9px; --c: var(--line-3);
  background-image:
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c));
  background-repeat: no-repeat;
  background-size:
    1px var(--arm), var(--arm) 1px, 1px var(--arm), var(--arm) 1px,
    1px var(--arm), var(--arm) 1px, 1px var(--arm), var(--arm) 1px;
  background-position:
    left 0 top var(--gap),      left var(--gap) top 0,
    right 0 top var(--gap),     right var(--gap) top 0,
    left 0 bottom var(--gap),   left var(--gap) bottom 0,
    right 0 bottom var(--gap),  right var(--gap) bottom 0;
}

/* ---------------------------------------------------------------- hero */
/* The home hero stays on paper — a printer sells paper, and the site should
   open on the thing it sells. The band under it is white, and the ones after
   alternate, so the punch arrives immediately anyway. The bottom rule is 2px
   of solid ink rather than a hairline: it is a trim edge, not a divider. */
.hero {
  position: relative; padding: 104px 0 84px;
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
}
/* Big Shoulders is condensed, so the display sizes here are far larger than a
   normal-width face would take at the same measure, and the max-width is set
   in ch against THAT face — 22ch of Big Shoulders is roughly 16ch of Archivo. */
.h-display {
  font-size: clamp(3.4rem, 9.6vw, 7.2rem); font-weight: 800;
  letter-spacing: -.015em; line-height: .88; margin: 24px 0 0; max-width: 22ch;
  text-wrap: balance;
}
/* One word of a headline set in the ink. It is the loudest thing on the page,
   which is why exactly one word gets it. */
.h-display .it, .it { font-style: normal; color: var(--accent); }
.hero-sub { margin-top: 26px; max-width: 62ch; font-size: 1.12rem; color: var(--tx-2); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; }

/* The hero's spec strip. Reads as the run sheet at the foot of a job ticket:
   mono key, display value, small note. */
.hero-meta {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
  margin-top: 60px; padding-top: 30px; border-top: 1px solid var(--line-2);
}
.hero-meta .item { padding-right: 22px; }
.hero-meta .item + .item { padding-left: 22px; border-left: 1px solid var(--line); }
.hero-meta .k {
  display: block; font-family: var(--mono); font-size: .64rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--tx-3);
}
.hero-meta .v {
  display: block; font-family: var(--display); font-size: 2rem; font-weight: 700;
  margin-top: 6px; letter-spacing: -.012em; line-height: 1; color: var(--tx);
}
.hero-meta .d { display: block; font-size: .82rem; color: var(--tx-3); margin-top: 7px; }

/* ------------------------------------------------------------- sections */
.section { padding: 96px 0; }
.section--tight { padding: 66px 0; }
/* The interior page hero is a dark band on EVERY page type — it is the half of
   the alternation a copy module cannot forget to write. */
.section--hero-sub, .page-hero {
  position: relative; padding: 68px 0 58px;
  border-bottom: 1px solid var(--line);
}
.section--hero-sub h1, .page-hero h1 {
  font-size: clamp(2.8rem, 7vw, 5.2rem); font-weight: 800;
  margin-top: 16px; letter-spacing: -.015em; line-height: .9; max-width: 24ch;
  text-wrap: balance;
}
/* service_page() emits a bare <p> intro under the h1 — give it the lead voice. */
.page-hero > .wrap > p, .section--hero-sub > .wrap > p {
  margin-top: 22px; max-width: 62ch; font-size: 1.06rem; color: var(--tx-2);
}
.page-hero .hero-actions, .section--hero-sub .hero-actions { margin-top: 32px; }
.page-hero > .wrap, .section--hero-sub > .wrap, .hero > .wrap { position: relative; z-index: 1; }

.h-section {
  font-size: clamp(2.4rem, 5vw, 3.8rem); font-weight: 800;
  letter-spacing: -.015em; line-height: .9; text-wrap: balance;
}
.lead { color: var(--tx-2); font-size: 1.04rem; max-width: 62ch; margin: 0; }
/* Big Shoulders draws an ascent plus descent of about 1.20em, and .h-section
   runs at line-height .9 — so a descender hangs roughly .15em below the box.
   At the 3.8rem ceiling that is 9px of glyph standing outside the heading,
   which lands in the first line of anything stacked directly underneath it
   ("Buying print, plainly." over its lead on the home page was doing exactly
   that). Give the space back. .stroke is deliberately not in this list: it is
   tucked up under the baseline on purpose. */
.h-section + p, .h-section + ul, .h-section + .chips { margin-top: 16px; }

.svc-head { display: grid; grid-template-columns: 1.25fr 1fr; gap: 40px; align-items: end; margin-bottom: 44px; }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: .82rem; color: var(--tx-3); }
.crumbs a { color: var(--tx-2); }
.crumbs a:hover { color: var(--accent); }
.crumbs .sep { color: var(--tx-3); }

/* --------------------------------------------------------- service cards */
.svc-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.svc {
  position: relative; display: block; padding: 32px 30px 28px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-card); overflow: hidden;
  color: var(--tx);
  transition: border-color .2s var(--ease);
}
/* A color bar along the head of the card — the control strip a pressman reads
   off the edge of a sheet. The ink, then the supporting cyan, in register, and
   only on hover. This is the one place cyan earns its keep. */
.svc::after {
  content: ""; position: absolute; inset: 0 0 auto; height: 3px;
  background: linear-gradient(90deg, var(--btn-bg) 0 38px, var(--cyan) 38px);
  transform: scaleX(0); transform-origin: left;
  transition: transform .28s var(--ease);
}
.svc:hover { border-color: var(--line-2); }
.svc:hover::after { transform: scaleX(1); }
/* A folio, top right, like the number in the corner of a signature. */
.svc .num { position: absolute; top: 26px; right: 28px; font-family: var(--mono); font-size: .7rem; color: var(--tx-3); }
.svc-ic {
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid var(--line-2); border-radius: var(--r-cta);
  background: var(--surface-2); color: var(--accent); margin-bottom: 20px;
}
.svc-ic svg { width: 22px; height: 22px; }
.svc h3 { font-size: 1.5rem; margin-bottom: 10px; color: var(--tx); }
.svc p { color: var(--tx-2); font-size: .94rem; margin-bottom: 16px; }
.svc ul { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; padding: 0; margin: 0 0 18px; }
.svc li {
  padding: 4px 10px; border-radius: var(--r-cta);
  background: var(--surface-2); border: 1px solid var(--line);
  font-family: var(--mono); font-size: .69rem; color: var(--tx-2);
}
.svc .more { font-size: .87rem; font-weight: 600; color: var(--accent); }
.svc:hover .more { color: var(--accent-hover); }

/* ------------------------------------------------------------- features */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.feature { padding: 28px 26px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); color: var(--tx); }
.fic {
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid var(--line-2); border-radius: var(--r-cta);
  background: var(--surface-2); color: var(--accent); margin-bottom: 18px;
}
.fic svg { width: 20px; height: 20px; }
.feature h3 { font-size: 1.3rem; margin-bottom: 8px; }
.feature p { color: var(--tx-2); font-size: .91rem; margin: 0; }

/* ---------------------------------------------------------------- steps */
/* "How a job runs" — prepress, proof, press, bindery, mail. Each step sits under
   its own trim rule, so the row reads as columns of a schedule rather than as
   cards. This is the section the brief singles out for a dark band; the rules
   below take their color from --tx and --line-2, so it works either way.
   One track per step: the home page emits five, and a four-column grid left the
   fifth stranded on a row of its own with three empty columns beside it. Below
   1141px the row cannot hold five, and the sequence stacks into one column
   rather than breaking 2 + 2 + 1. */
.steps { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0 26px; }
.step { padding-top: 22px; border-top: 2px solid var(--tx); }
.step + .step { border-top-color: var(--line-2); }
.step .n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 28px; height: 28px; padding: 0 7px;
  font-family: var(--mono); font-size: .76rem; font-weight: 500;
  color: var(--accent); border: 1px solid var(--accent); border-radius: var(--r-cta);
}
.step h3 { font-size: 1.35rem; margin: 16px 0 8px; }
.step p { color: var(--tx-2); font-size: .91rem; margin: 0; }

/* ------------------------------------------------------------- products */
/* Thirteen items on /products, and a strip of them on the home page. Small,
   flat, evenly ruled — a stock list, not thirteen marketing cards. */
.prod-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.prod {
  padding: 24px 24px 22px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-card);
  color: var(--tx);
  transition: border-color .2s var(--ease);
}
.prod:hover { border-color: var(--line-2); }
.prod h3 { font-size: 1.28rem; margin-bottom: 7px; }
/* A short rule of ink under each name — the stroke, reduced to its simplest
   possible form, thirteen times over. */
.prod h3::after {
  content: ""; display: block; width: 26px; height: 2px;
  background: var(--accent); margin-top: 10px;
}
.prod p { color: var(--tx-2); font-size: .89rem; margin: 10px 0 0; }
.prod .more { display: inline-block; margin-top: 12px; font-size: .84rem; font-weight: 600; color: var(--accent); }

/* -------------------------------------------------------- spec sheet */
/* /equipment. Mono throughout: a press list should look like the inventory it
   is. .spec-head rules off to the right edge; .spec-list runs two columns once
   there is width for it. */
.spec { padding: 28px 28px 24px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); color: var(--tx); }
.spec + .spec { margin-top: 16px; }
.spec-head {
  display: flex; align-items: center; gap: 14px; margin-bottom: 18px;
  font-family: var(--mono); font-size: .72rem; font-weight: 500;
  letter-spacing: .15em; text-transform: uppercase; color: var(--accent);
}
.spec-head::after { content: ""; flex: 1; height: 1px; background: var(--line); }
/* Two columns wherever there is width for them — an equipment list runs to
   sixteen items and a single tall column wastes the page. */
.spec-list { list-style: none; margin: 0; padding: 0; column-count: 2; column-gap: 36px; }
.spec-list li {
  position: relative; padding: 8px 0 8px 20px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: .84rem; line-height: 1.5; color: var(--tx-2);
  break-inside: avoid;
}
.spec-list li::before {
  content: ""; position: absolute; left: 2px; top: 16px;
  width: 7px; height: 1px; background: var(--line-3);
}
.spec-list li:first-child { border-top: 0; }

/* ======================================================= published photos */
/* .fig — one of the 20 images in assets/photos with its caption.
   THE HARD CONSTRAINT: these are 300-400px originals. Nothing here sets
   width:100% on an <img>, and nothing here can, because that is the rule that
   would upscale them. The intrinsic width/height attributes from
   manifest.py size the box; max-width only ever shrinks it inside a narrow
   column. Small and precise is the design, not a compromise. */
.fig { margin: 0; display: flex; flex-direction: column; gap: 0; max-width: 100%; }
.fig img {
  display: block; height: auto; max-width: 100%;
  border-radius: var(--r-card);
}
.fig figcaption {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: .73rem; line-height: 1.55;
  letter-spacing: .015em; color: var(--tx-3);
  max-width: 46ch;
}

/* .fig--plate — the manufacturer product shots. They are photographed on pure
   white, so multiply drops the white out and leaves the machine silhouetted
   on the band's own stock, which is what makes them read as spec-sheet
   illustrations rather than as pasted-in stock photos. */
.fig--plate img {
  mix-blend-mode: multiply;
  border-radius: 0;
}
/* Multiply against near-black would erase them, so on a dark band the plate
   gets a paper swatch instead — the same move as the logo lockup, and the
   same reason: a white-ground photograph needs a light ground under it. */
.band--ink .fig--plate img, .cta .fig--plate img, .page-hero .fig--plate img,
.section--hero-sub .fig--plate img, .site-footer .fig--plate img {
  mix-blend-mode: normal;
  background: var(--paper);
  padding: 14px;
  border-radius: var(--r-card);
}

/* .plate-grid — /equipment's illustrated spec sheet: one plate standing beside
   the machines it names. The image column is capped at 300px because that is
   the widest plate in the manifest, so the track never asks an image to be
   bigger than it is. */
.plate-grid {
  display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: 28px 36px; align-items: start;
}
.plate-grid > .spec { margin-top: 0; }
/* Used as a gallery of plates rather than as one plate beside a spec. */
.plate-grid:not(:has(.spec)) { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.plate-grid + .plate-grid { margin-top: 40px; padding-top: 40px; border-top: 1px solid var(--line); }

/* ---------------------------------------------------------- service areas */
.city-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.city-card {
  display: flex; flex-direction: column; padding: 28px 26px 24px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card);
  color: var(--tx);
  transition: border-color .2s var(--ease);
}
.city-card:hover { border-color: var(--line-2); }
.city-card h3 { font-size: 1.5rem; margin-bottom: 9px; }
.city-card .k {
  display: block; font-family: var(--mono); font-size: .64rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--tx-3); margin-bottom: 12px;
}
.city-card p { color: var(--tx-2); font-size: .91rem; margin: 0 0 16px; }
.city-card .more { margin-top: auto; font-size: .86rem; font-weight: 600; color: var(--accent); }
/* The "nearby towns" line at the foot of a location page or card. */
.nearby {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: .72rem; letter-spacing: .04em; color: var(--tx-3);
}
.nearby a { color: var(--accent); }
.nearby a:hover { color: var(--accent-hover); text-decoration: underline; text-underline-offset: 3px; }

/* ----------------------------------------------------------------- chips */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.chip {
  padding: 8px 15px; border-radius: var(--r-cta);
  /* The fill is one step off the ground (1.13:1 on a white band), so the border
     is the only thing separating a chip from the body text around it — which
     makes it a control boundary at --rule-strong, not a hairline. */
  background: var(--surface); border: 1px solid var(--rule-strong);
  font-size: .88rem; font-weight: 500; color: var(--tx);
  transition: border-color .18s var(--ease), color .18s var(--ease), background .18s var(--ease);
}
.chip:hover { border-color: var(--accent); color: var(--accent-hover); background: var(--accent-soft); }

/* --------------------------------------------------------------- callout */
/* A bordered note inside .prose — the marginal instruction on a job bag. */
.callout {
  margin: 30px 0; padding: 20px 24px;
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--accent); border-radius: 0 var(--r-card) var(--r-card) 0;
  color: var(--tx);
}
.callout p { color: var(--tx-2); font-size: .93rem; }
.callout p:last-child { margin-bottom: 0; }
.callout b, .callout strong { color: var(--tx); }

/* ------------------------------------------------------------------- FAQ */
.faq-grid { display: grid; grid-template-columns: .85fr 1.15fr; gap: 48px; align-items: start; }
.faq-list { display: flex; flex-direction: column; gap: 8px; }
.faq-list details, .faq-block details {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-card); overflow: hidden;
  color: var(--tx);
  transition: border-color .18s var(--ease);
}
details[open] { border-color: var(--line-2); }
summary {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px 20px; cursor: pointer; list-style: none;
  font-family: var(--display); font-size: 1.18rem; font-weight: 700;
  letter-spacing: -.01em; line-height: 1.12; color: var(--tx);
}
summary::-webkit-details-marker { display: none; }
summary:hover { color: var(--accent-hover); }
.faq-list summary:focus-visible, .faq-block summary:focus-visible {
  outline: 2px solid var(--focus); outline-offset: -3px;
}
.faq-icon { position: relative; flex: none; width: 15px; height: 15px; }
.faq-icon::before, .faq-icon::after {
  content: ""; position: absolute; inset: 50% 0 auto; height: 2px; background: var(--accent);
  transform: translateY(-50%); transition: transform .22s var(--ease), opacity .22s;
}
.faq-icon::after { transform: translateY(-50%) rotate(90deg); }
details[open] .faq-icon::after { transform: translateY(-50%) rotate(0); opacity: 0; }
.answer { padding: 0 20px 18px; color: var(--tx-2); font-size: .94rem; }
.answer p { margin: 0; }
.answer a, .prose a, .lead a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.answer a:hover, .prose a:hover, .lead a:hover { color: var(--accent-hover); }
.faq-block { margin-bottom: 40px; }
.faq-block .h-section { font-size: 1.9rem; margin-bottom: 18px; }

/* ----------------------------------------------------------------- prose */
/* ~65 characters is the measure. Instrument Sans at 16px/1.65 puts that at
   roughly 640px, and 65ch measures it directly against the face in use. */
.prose { max-width: 65ch; line-height: 1.65; }
.prose h2 { font-size: 2rem; margin: 46px 0 14px; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: 1.4rem; margin: 30px 0 10px; }
.prose p, .prose li { color: var(--tx-2); }
.prose b, .prose strong { color: var(--tx); font-weight: 600; }
.prose ul { padding-left: 1.1em; }
.prose li { margin-bottom: 7px; }
.prose li::marker { color: var(--accent); }
.prose .fig { margin: 30px 0; }

/* service_page() wraps its prose + sidebar in .layout; the about page uses
   .svc-body. Same two-column treatment for both. */
.svc-body, .layout { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, .95fr); gap: 48px; align-items: start; }

/* ------------------------------------------------------------ aside card */
.aside-card { position: sticky; top: calc(var(--head-h) + 24px); }
.aside-card .inner {
  padding: 30px 28px; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: var(--r-card);
  border-top: 3px solid var(--accent);
  color: var(--tx);
}
.aside-card h2 { font-size: 1.55rem; margin: 18px 0 10px; }
.aside-card p { color: var(--tx-2); font-size: .93rem; }
.aside-card .btn { width: 100%; margin-top: 4px; }
.aside-card .meta { display: flex; flex-direction: column; gap: 2px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.aside-card .meta a { display: flex; justify-content: space-between; gap: 14px; padding: 7px 0; font-size: .87rem; }
.aside-card .meta .k { font-family: var(--mono); font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; color: var(--tx-3); padding-top: 2px; }
.aside-card .meta .v { color: var(--tx); font-weight: 500; }
.aside-card .meta a:hover .v { color: var(--accent-hover); }

/* -------------------------------------------------------------- CTA band */
/* The closing CTA is one of the two guaranteed dark bands. It is engine-emitted
   by cta_block(), so every page ends on near-black whatever its copy module
   does, and it runs straight into the footer, which is deeper again. */
.cta { border-top: 1px solid var(--line-2); }
.cta-grid { display: grid; grid-template-columns: 1.2fr .9fr; gap: 48px; align-items: center; }
.cta h2 { font-size: clamp(2.4rem, 5vw, 3.6rem); font-weight: 800; letter-spacing: -.015em; line-height: .9; }
.cta p { color: var(--tx-2); margin-top: 16px; max-width: 52ch; }
.cta-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

.contact-card { padding: 28px 26px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-card); color: var(--tx); }
.contact-card .row { display: flex; justify-content: space-between; gap: 18px; padding: 11px 0; border-bottom: 1px solid var(--line); font-size: .92rem; }
.contact-card .row:last-of-type { border-bottom: 0; }
.contact-card .k { color: var(--tx-3); font-family: var(--mono); font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; padding-top: 4px; }
.contact-card .v { text-align: right; color: var(--tx); }
.contact-card a { color: var(--accent); text-align: right; }
.contact-card a:hover { color: var(--accent-hover); }
/* Variant used where the card sits on a page band rather than inside the CTA. */
.contact-card--panel { background: var(--surface-2); border-color: var(--line-2); }

/* ----------------------------------------------------------------- forms */
/* /request-a-quote and the contact page. Fields are ruled boxes with a mono
   label above — a form you would fill in with a pen. Every color here is a
   band token, so the same markup works on paper and on the ink band. */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 20px; }
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field--wide { grid-column: 1 / -1; }
.field > label, .field > span {
  font-family: var(--mono); font-size: .68rem; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase; color: var(--tx-3);
}
.field .req { color: var(--accent); }

input, select, textarea {
  width: 100%; padding: 12px 14px;
  font-family: var(--body); font-size: .95rem; line-height: 1.45; color: var(--tx);
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: var(--r-cta);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
textarea { min-height: 150px; resize: vertical; }
select {
  appearance: none;
  /* A caret drawn in ink rather than an image request. currentColor, so it
     flips with the band along with everything else. */
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-size: 6px 6px, 6px 6px;
  background-position: right 17px center, right 11px center;
  background-repeat: no-repeat;
  padding-right: 34px;
}
input::placeholder, textarea::placeholder { color: var(--tx-3); opacity: 1; }
input:hover, select:hover, textarea:hover { border-color: var(--tx-3); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
input[type="checkbox"], input[type="radio"] { width: auto; padding: 0; accent-color: var(--btn-bg); }
input[type="file"] { padding: 10px 12px; font-family: var(--mono); font-size: .82rem; }
input[type="file"]::file-selector-button {
  margin-right: 12px; padding: 8px 14px; cursor: pointer;
  font-family: var(--body); font-size: .84rem; font-weight: 600;
  color: var(--btn-fg); background: var(--btn-bg); border: 0; border-radius: var(--r-cta);
}

.form-note { margin: 16px 0 0; font-size: .84rem; color: var(--tx-3); }
.form-note a { color: var(--accent); }

/* .form-msg is this build's status box; .form-status is the element the shared
   site.js writes into on the contact form. Same treatment, so whichever the
   page uses is styled. Guard the hidden attribute — these start hidden. */
.form-msg, .form-status {
  margin-top: 18px; padding: 14px 17px;
  background: var(--surface); border: 1px solid var(--line-2);
  border-left: 3px solid var(--tx-3); border-radius: 0 var(--r-cta) var(--r-cta) 0;
  font-size: .91rem; color: var(--tx-2);
}
.form-msg[hidden], .form-status[hidden] { display: none; }
.form-msg.ok, .form-status.ok { border-left-color: var(--cyan); background: var(--surface-2); color: var(--tx); }
.form-msg.err, .form-status.err { border-left-color: var(--accent); background: var(--accent-soft); color: var(--tx); }
.form-msg a, .form-status a { color: var(--accent); }

/* ------------------------------------------------------------ send a file */
.drop-zone {
  display: grid; place-items: center; gap: 10px;
  padding: 48px 24px; text-align: center;
  background: var(--surface); border: 2px dashed var(--rule-strong); border-radius: var(--r-card);
  color: var(--tx);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.drop-zone svg { width: 32px; height: 32px; color: var(--accent); }
.drop-zone p { margin: 0; color: var(--tx-2); font-size: .94rem; }
.drop-zone b { color: var(--tx); }
.drop-zone .form-note { margin-top: 2px; }
/* The "Choose files" label is a control, not a field caption — see the note on
   .field > label. It has to read and behave like the link it is. */
.drop-zone label {
  font: inherit; letter-spacing: normal; text-transform: none;
  color: var(--accent); font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.drop-zone label:hover { color: var(--accent-hover); }
.drop-zone label:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.drop-zone.drag { border-color: var(--accent); border-style: solid; background: var(--accent-soft); }

.file-list { list-style: none; margin: 20px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.file-list li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px 14px; align-items: center;
  padding: 12px 15px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card);
}
.file-list .k { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9rem; color: var(--tx); }
.file-list .v { font-family: var(--mono); font-size: .74rem; color: var(--tx-3); }

/* Upload progress. Works either way a page drives it: a child element whose
   width is set, or --p set on the track itself. */
.bar { grid-column: 1 / -1; height: 4px; background: var(--surface-2); border-radius: 999px; overflow: hidden; }
.bar > span, .bar > i, .bar > b { display: block; height: 100%; width: 0; background: var(--btn-bg); transition: width .25s linear; }
.bar:empty::after { content: ""; display: block; height: 100%; width: var(--p, 0%); background: var(--btn-bg); transition: width .25s linear; }

/* ---------------------------------------------------------------- footer */
/* The deepest ground on the site — #0B0C0E, a step below the .cta band that
   runs into it, so the page closes on black rather than fading out on paper.
   All of its tokens were inverted in THE BANDS block above. */
.site-footer { border-top: 1px solid var(--line); padding: 0 0 26px; overflow: hidden; }
/* The closing band, above the footer proper. A raised panel with the ink down
   its leading edge — the last press mark on the sheet. */
.foot-cta {
  display: flex; justify-content: space-between; align-items: center; gap: 32px; flex-wrap: wrap;
  margin: 56px 0 52px; padding: clamp(30px, 4vw, 44px) clamp(26px, 4vw, 42px);
  background: var(--surface); border: 1px solid var(--line);
  border-left: 4px solid var(--accent); border-radius: 0 var(--r-card) var(--r-card) 0;
}
.foot-cta-h { font-size: clamp(2.2rem, 5vw, 3.6rem); font-weight: 800; letter-spacing: -.015em; line-height: .9; margin-top: 16px; max-width: 24ch; }
.foot-cta-h .it { color: var(--accent); }
.foot-cta .btn { flex: none; }

.foot-top { display: grid; grid-template-columns: 1fr 2.2fr; gap: 48px; padding-top: 8px; }
/* build.py writes style="color:var(--paper)" on the brand word inside this
   block. BRAND_HTML is an empty string, so the span has nothing in it and is
   hidden by .brand span:empty above; and were it ever refilled, --paper is now
   the correct type color here, because the footer is a dark ground. */
.foot-brand .brand { align-items: flex-start; }
.foot-brand p { color: var(--tx-2); font-size: .9rem; margin-top: 18px; max-width: 36ch; }
.foot-cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: 28px; }
.foot-col h3 {
  font-family: var(--mono); font-size: .66rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent);
  margin-bottom: 12px;
}
.foot-col a, .foot-col .v { display: block; padding: 5px 0; font-size: .88rem; color: var(--tx-2); }
.foot-col a:hover { color: var(--accent-hover); }
.foot-bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 14px;
  margin-top: 48px; padding-top: 20px; border-top: 1px solid var(--line);
  font-size: .81rem; color: var(--tx-3);
}
.foot-bottom a { color: var(--tx-3); }
.foot-bottom a:hover { color: var(--accent-hover); }

/* ------------------------------------------------------------ chat widget */
/* CHAT is False in the profile, so this never renders today. Kept and remapped
   onto the new palette so turning it on is one flag, not a restyle. */
.sk-chat { position: fixed; right: 22px; bottom: 22px; z-index: 120; }
.sk-fab {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 20px; border-radius: var(--r-pill);
  background: var(--btn-bg); color: var(--btn-fg); border: 0; cursor: pointer;
  font-family: var(--body); font-size: .92rem; font-weight: 600;
  box-shadow: 0 8px 24px rgba(11, 12, 14, .18);
  transition: background .18s var(--ease);
}
.sk-fab:hover { background: var(--btn-bg-hi); }
.sk-fab .mk { width: 18px; height: 21px; display: block; }
.fab-dot { width: 7px; height: 7px; border-radius: 50%; background: #fff; opacity: .55; }
.sk-panel {
  position: absolute; right: 0; bottom: 0; width: min(370px, calc(100vw - 44px));
  display: flex; flex-direction: column; max-height: min(560px, calc(100vh - 44px));
  background: var(--white); border: 1px solid var(--line-2); border-radius: var(--r-card);
  box-shadow: 0 20px 50px rgba(11, 12, 14, .20); overflow: hidden;
}
.sk-panel[hidden] { display: none; }
.sk-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; background: var(--paper); border-bottom: 2px solid var(--accent); }
.sk-ident { display: flex; align-items: center; gap: 10px; }
.sk-avatar { width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--r-cta); background: var(--accent-soft); }
.sk-avatar .mk { width: 16px; height: 19px; }
.sk-headtext { display: flex; flex-direction: column; }
.sk-title { font-family: var(--display); font-weight: 700; font-size: 1.1rem; color: var(--ink); }
.sk-status { display: flex; align-items: center; gap: 6px; font-size: .72rem; color: var(--ink-3); }
.sk-status .live { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.sk-x { background: none; border: 0; color: var(--ink-3); cursor: pointer; padding: 4px; }
.sk-x svg { width: 17px; height: 17px; }
.sk-x:hover { color: var(--ink); }
.sk-log { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 10px; font-size: .92rem; color: var(--ink-2); }
.sk-input { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }
.sk-input textarea {
  flex: 1; min-height: 0; resize: none; padding: 10px 12px; border-radius: var(--r-cta);
  background: var(--paper); border: 1px solid var(--line-2); color: var(--ink);
  font-family: var(--body); font-size: .9rem; line-height: 1.45;
}
.sk-send { flex: none; width: 40px; border-radius: var(--r-cta); background: var(--btn-bg); color: var(--btn-fg); border: 0; cursor: pointer; }
.sk-send svg { width: 18px; height: 18px; }
.sk-foot { margin: 0; padding: 0 14px 12px; font-size: .72rem; color: var(--ink-3); }
.sk-foot a { color: var(--accent); }
/* Honeypot: off-screen, never focusable by sight. */
.hp { position: absolute !important; left: -9999px !important; }

/* ---------------------------------------------------------------- reveal */
.reveal { opacity: 1; transform: none; }
html.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s var(--ease), transform .6s var(--ease); }
html.js .reveal.in { opacity: 1; transform: none; }

/* ======================================================== responsive pass
   320px to 1440px. Three stops: 1140 (the nav collapse, plus every two-column
   grid), 860 (tablet), 560 (phone). Nothing below 320px is designed for, and
   nothing above 1440 needs to be: --wrap caps at 1180.
   ==================================================================== */

/* The nav breakpoint is measured, not guessed. Omega's nav row — the 114px
   logo, two dropdown triggers, FOUR flat links (Products, Equipment, About,
   Contact) and the quote button — measures 934px with the webfonts loaded,
   and it is WIDER than that until Instrument Sans arrives, because the
   fallback stack sets looser. At a 1141px viewport the row has 1086px to
   stand in, so collapsing to the burger at 1140px leaves 152px of slack and
   the row cannot overrun the gutter mid-font-swap. It was 1080px while the
   nav had three flat links; adding /contact as a fourth is what moved it, and
   the logo lockup is wider than the text brand it replaced. */
@media (max-width: 1140px) {
  .burger { display: block; }
  /* Full-height sheet, not a hanging panel: a short menu that stops halfway
     leaves the page's own hero buttons showing underneath, which duplicates
     the pinned CTA below. dvh so mobile browser chrome does not clip the foot
     of the list. This is fixed to the VIEWPORT — see the note on .site-header
     about never giving that element a backdrop-filter. */
  .nav-links {
    position: fixed; top: var(--head-h); left: 0; right: 0;
    height: calc(100vh - var(--head-h));
    height: calc(100dvh - var(--head-h));
    flex-direction: column; align-items: stretch;
    gap: 2px; padding: 14px 20px 24px; background: var(--paper);
    display: none; overflow-y: auto; overscroll-behavior: contain;
  }
  /* The contract with site.js — the class it toggles is what opens the menu. */
  .nav.nav-menu-open .nav-links { display: flex; }
  .nav-links > a, .drop-trigger { padding: 12px 4px; font-size: 1.02rem; }
  /* The current-page rule turns on its side when the row does. */
  .nav-links > a[aria-current], .drop-trigger[aria-current] { box-shadow: inset 2px 0 0 var(--accent); padding-left: 12px; }
  .has-dropdown { position: static; }
  .dropdown {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; background: none; padding: 0 0 6px 12px; display: none;
    border-left: 1px solid var(--line);
  }
  .dropdown.open { display: block; }
  .has-dropdown:focus-within .dropdown { display: block; }
  /* A link trigger has no toggle behind it on this breakpoint, so its submenu
     is simply always open and its caret is not a control. */
  .has-dropdown:has(> a.drop-trigger) .dropdown { display: block; }
  .has-dropdown:has(> a.drop-trigger) .drop-caret { display: none; }
  .dropdown--mega { min-width: 0; }
  .dropdown a { padding: 8px 10px; }
  .drop-cols { grid-template-columns: 1fr; }
  /* The quote button will not fit beside the logo and the burger, but the
     engine renders it in .nav-cta — a SIBLING of .nav-links — so it cannot be
     moved into the menu markup. Hide it in the bar and, while the menu is
     open, pin it across the foot of the screen: the one thing a visitor came
     to do, under their thumb. Keyed off .nav-menu-open, the same class site.js
     toggles, so no new JS contract. The open menu reserves room for it. */
  .nav-cta .btn { display: none; }
  .nav.nav-menu-open .nav-links { padding-bottom: 92px; }
  body.menu-open { overflow: hidden; }
  .nav.nav-menu-open .nav-cta .btn {
    display: inline-flex; position: fixed; left: 20px; right: 20px; bottom: 20px;
    z-index: 101; padding: 15px 20px; font-size: 1rem;
    box-shadow: 0 6px 20px rgba(11, 12, 14, .16);
  }

  .svc-head, .faq-grid, .cta-grid, .svc-body, .layout, .foot-top { grid-template-columns: 1fr; gap: 32px; }
  .feature-grid, .prod-grid, .city-grid { grid-template-columns: repeat(2, 1fr); }
  .foot-cols { grid-template-columns: repeat(2, 1fr); gap: 24px 28px; }
  /* One per row: the heavy rule marks the top of the sequence, and every step
     under it takes the light one. */
  .steps { grid-template-columns: 1fr; gap: 26px; }
  .step + .step { border-top-color: var(--line-2); }
  .hero-meta { grid-template-columns: repeat(2, 1fr); row-gap: 26px; }
  .hero-meta .item:nth-child(odd) { padding-left: 0; border-left: 0; }
  .aside-card { position: static; }
  /* The plate column stops leading and sits above the list it illustrates. */
  .plate-grid { grid-template-columns: minmax(0, 260px) minmax(0, 1fr); gap: 24px 28px; }
}

@media (max-width: 860px) {
  .svc-grid { grid-template-columns: 1fr; }
  .section { padding: 68px 0; }
  .section--tight { padding: 52px 0; }
  .section--hero-sub, .page-hero { padding: 52px 0 44px; }
  .hero { padding: 72px 0 58px; }
  .hero-meta { margin-top: 44px; }
  /* Crop marks crowd the type once the band is this narrow — pull them. */
  .hero::after, .page-hero::after, .section--hero-sub::after { display: none; }
  .form-grid { grid-template-columns: 1fr; }
  .spec-list { column-count: 1; }
  .foot-cta { margin: 44px 0; }
  .plate-grid { grid-template-columns: 1fr; gap: 22px; }
  .plate-grid > .fig { justify-self: start; }
  .plate-grid + .plate-grid { margin-top: 32px; padding-top: 32px; }
  .brand-logo { width: 104px; }
  .site-footer .brand-logo { width: 132px; }
}

@media (max-width: 560px) {
  .feature-grid, .prod-grid, .city-grid { grid-template-columns: 1fr; }
  .hero-meta { grid-template-columns: 1fr; }
  .hero-meta .item, .hero-meta .item + .item { padding: 0; border-left: 0; }
  .hero-meta .item + .item { padding-top: 20px; border-top: 1px solid var(--line); }
  .foot-cols { grid-template-columns: 1fr; }
  .foot-cta { flex-direction: column; align-items: flex-start; gap: 24px; }
  .contact-card .row { flex-direction: column; gap: 4px; }
  .contact-card .v, .contact-card a { text-align: left; }
  .spec, .foot-cta { padding-left: 20px; padding-right: 20px; }
  .file-list li { grid-template-columns: 1fr; }
  /* Full-bleed tap targets: two 44px-high buttons side by side do not fit. */
  .hero-actions .btn, .cta-actions .btn, .aside-card .btn, .foot-cta .btn, .field--wide .btn { width: 100%; }
  .hero-actions, .cta-actions { gap: 10px; }
  /* The stroke is ornament; at 320px it competes with the words it is meant to
     sit under, so it comes down in size rather than out of the page. */
  .stroke { width: clamp(130px, 46vw, 190px); }
  :is(h1, h2, h3, .h-display, .h-section, .foot-cta-h, .hero-sub, .lead) + .stroke { margin-top: -12px; }
  .fig figcaption { font-size: .71rem; }
}

@media (max-width: 380px) {
  .wrap { width: calc(100% - 32px); }
  .brand-logo { width: 96px; }
  .h-display { font-size: clamp(2.9rem, 13vw, 3.6rem); }
}

/* ------------------------------------------------------- reduced motion */
/* .reveal must be a genuine no-op, not a faster animation: site.js already
   adds .in immediately when the media query matches, but a visitor who flips
   the setting mid-session would otherwise be left looking at an opacity:0
   page. The !important is load-bearing — html.js .reveal is more specific. */
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.in, html.js .reveal, html.js .reveal.in {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto; }
}
