/* ==========================================================================
   DSS Corporate — stylesheet
   Plain CSS, no build step. Consumes css/tokens.css exclusively — no
   hardcoded color/size/radius below this line.
   ========================================================================== */

/* ---- fonts --------------------------------------------------------------
   Self-hosted, latin-only subset (US-English corporate record — no need
   for the other Google-served unicode ranges). Big Shoulders and Public
   Sans are variable files that cover our two static weights each from one
   download; IBM Plex Mono ships two real static files. */
@font-face {
  font-family: "Big Shoulders";
  font-style: normal;
  font-weight: 600 800;
  font-display: swap;
  src: url("/fonts/big-shoulders-var.woff2") format("woff2");
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/fonts/public-sans-var.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-500.woff2") format("woff2");
}

/* ---- reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; border-radius: var(--radius); }
html, body, h1, h2, h3, p, dl, dd, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }

/* ---- base ------------------------------------------------------------------
   The grain texture: a procedural, hand-tuned SVG noise tile (~545 bytes,
   inlined — no HTTP request, no raster asset). Standard "colored noise"
   filter chain: feTurbulence -> luminanceToAlpha -> feComponentTransfer
   (linear slope 0.09, i.e. ~9% peak alpha) -> feFlood (iron) -> feComposite
   "in". First attempt used a single feColorMatrix with a small alpha term
   and rendered as solid black in real Chromium (proven visually — Playwright
   screenshot, not just computed-style, caught it; getComputedStyle reported
   the CORRECT background-color the whole time, so a style-only check would
   have missed this). Verified worst-case (pure-black pixel) contrast impact
   on iron/bone body text: 12.59:1 -> no lower than 10.07:1 at 10% alpha, and
   this rebuilt version visually confirmed as a faint tiled grain, not a
   fill. Sits behind text via background-image; never intercepts pointer
   events (it's not an element). */
html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
}
body {
  background-color: var(--color-bone);
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMjAiIGhlaWdodD0iMjIwIj48ZmlsdGVyIGlkPSJuIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iMC44NSIgbnVtT2N0YXZlcz0iMiIgc3RpdGNoVGlsZXM9InN0aXRjaCIgcmVzdWx0PSJub2lzZSIvPjxmZUNvbG9yTWF0cml4IGluPSJub2lzZSIgdHlwZT0ibHVtaW5hbmNlVG9BbHBoYSIgcmVzdWx0PSJhbHBoYSIvPjxmZUNvbXBvbmVudFRyYW5zZmVyIGluPSJhbHBoYSIgcmVzdWx0PSJmYWRlZEFscGhhIj48ZmVGdW5jQSB0eXBlPSJsaW5lYXIiIHNsb3BlPSIwLjA5IiBpbnRlcmNlcHQ9IjAiLz48L2ZlQ29tcG9uZW50VHJhbnNmZXI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMyYjI3MjMiIHJlc3VsdD0idGludCIvPjxmZUNvbXBvc2l0ZSBpbj0idGludCIgaW4yPSJmYWRlZEFscGhhIiBvcGVyYXRvcj0iaW4iLz48L2ZpbHRlcj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWx0ZXI9InVybCgjbikiLz48L3N2Zz4=");
  background-repeat: repeat;
  color: var(--color-iron);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.55;
  min-height: 100vh;
}

/* ---- typography ------------------------------------------------------------ */
h1, h2, h3 { text-wrap: balance; font-family: var(--font-display); font-weight: 800; }

h1 {
  font-size: var(--text-display);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
h2 {
  font-size: var(--text-lg);
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 600;
}
h3 {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: 0;
}

p { max-width: 68ch; text-wrap: pretty; }

.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-iron-soft);
}

/* Tabular figures apply broadly (every number on the page, per Article 3) —
   but the MONO FAMILY does not: it is scoped to exactly one block, the
   entity plate (.plate__block dd, below). Every other numeral-bearing
   element gets tabular-nums in the body face, never a mono font-family. */
a[href^="tel:"] {
  font-variant-numeric: tabular-nums;
  /* Kassia iteration-1 BLOCKER: phone wrapped mid-number at 375px ("Call
     610-" / "228-0887."). One rule on the shared tel: selector fixes every
     instance (plate, contact, footer) at the root, not per-caller. */
  white-space: nowrap;
}
.contact__address,
.footer__address {
  font-variant-numeric: tabular-nums;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---- skip link --------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: var(--space-s);
  top: var(--space-s);
  z-index: 10;
  background: var(--color-iron);
  color: var(--color-bone);
  padding: var(--space-s) var(--space-m);
  font-family: var(--font-body);
  font-weight: 600;
  /* Kassia iteration-1 BLOCKER: top:-3rem (-48px) hid only 48px of a 51.9px
     box, welding a ~4x175px bar to 0,0 on every page. transform + -150%
     clears the box regardless of its exact height (a hardcoded top re-breaks
     the moment padding/font-size changes); focus returns it to its natural
     top:var(--space-s) position, unchanged from before. */
  transform: translateY(-150%);
  transition: transform 0.15s ease-out;
}
.skip-link:focus {
  transform: translateY(0);
}

/* ---- focus -------------------------------------------------------------
   Never a bare outline:none — every interactive element gets a real,
   visible replacement. */
a, button {
  outline-offset: 2px;
}
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--color-brass);
  outline-offset: 3px;
}

/* ---- layout primitives --------------------------------------------------
   Asymmetric: content is pinned toward the left edge with a responsive
   gutter, never centered. Extra space at wide viewports collects on the
   right, unused on purpose. */
.section-inner {
  max-width: calc(var(--content-max) + var(--space-m) + var(--label-col));
  margin-left: var(--edge-pad);
  /* Kassia iteration-1 HIGH: was margin-right:auto, which resolves to 0
     below max-width -- content sat flush on the right screen edge at 375px
     (the plate frame rendered three-sided). A fixed right pad fixes mobile;
     above max-width the box becomes over-constrained (CSS2.1 10.3.3) and
     the browser recomputes margin-right to absorb the leftover space
     anyway, so the wide-viewport right-collecting void is unchanged. */
  margin-right: var(--edge-pad);
  padding-block: var(--space-l);
}
main > section:first-child .section-inner,
section + section .section-inner,
footer .section-inner {
  padding-top: 0;
}

/* the row: label-in-right-margin on wide viewports, label-above-value on
   mobile. DOM order is always label then value/content — only the visual
   column position changes, so screen-reader order never contradicts sight
   order. */
.row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.35rem;
  padding-block: var(--space-m);
  border-top: 1px solid var(--color-hairline);
}
.row:first-child { border-top: none; }
/* Kassia iteration-1 MEDIUM: :first-child matches the roster's first <li>
   but not founder/contact's .row (3rd child of .section-inner, after .rule
   and <h2>) -- each got sandwiched between the brass rule and a stray
   hairline. Founder/contact each hold exactly one .row, so removing its
   top border unconditionally is safe. */
.founder .row, .contact .row { border-top: none; }
.row__label {
  order: -1;
}
@media (min-width: 640px) {
  .row {
    grid-template-columns: minmax(0, 1fr) var(--label-col);
    column-gap: var(--space-m);
    align-items: start;
  }
  .row__label {
    order: 0;
    grid-column: 2;
    grid-row: 1;
    padding-top: 0.2em;
  }
  .row__main {
    grid-column: 1;
    grid-row: 1;
  }
}

/* ---- the signature motion moment ----------------------------------------
   Exactly one: the section-boundary rules draw in once on load, a
   single orchestrated scaleX with a ~40ms stagger. Nothing else on this
   page moves. Transform only (no layout thrash), degrades to a static
   line under prefers-reduced-motion. */
.rule {
  height: 1px;
  background: var(--color-rule);
  transform: scaleX(0);
  transform-origin: left;
  animation: draw-in var(--motion-draw) cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
  animation-delay: calc(var(--i, 0) * var(--motion-stagger));
}
@keyframes draw-in {
  to { transform: scaleX(1); }
}
@media (prefers-reduced-motion: reduce) {
  .rule {
    animation: none;
    transform: scaleX(1);
  }
}

/* ==========================================================================
   THE PLATE (hero / header)
   ========================================================================== */
.plate {
  border-bottom: none;
}
.plate__frame {
  border: 1px solid var(--color-hairline);
  padding: var(--space-l) var(--space-m);
}
.plate__eyebrow { margin-bottom: var(--space-s); }
.plate__name { margin-bottom: var(--space-m); }
.plate__desc {
  color: var(--color-iron-soft);
  margin-bottom: var(--space-l);
}

.plate__block { display: block; }
.plate__block .row { border-top-color: var(--color-hairline); }
.plate__block dt { font: inherit; }
.plate__block dd {
  font-family: var(--font-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   ROSTER (what it builds)
   ========================================================================== */
.roster .row__main a {
  text-decoration-color: var(--color-hairline);
  text-underline-offset: 0.2em;
}
.roster .row__main a:hover {
  text-decoration-color: var(--color-brass);
}
.roster h3 { margin-bottom: 0.35rem; }
.roster p.row__desc { color: var(--color-iron-soft); font-size: var(--text-base); }

/* ==========================================================================
   INDUSTRIES (slide-37: 3 equal columns on mobile, one caption style)
   Weebly live used a 3-col table with mixed <font size> on captions, so
   wraps like "Banking & Finance" broke the row. CSS grid + one class.
   ========================================================================== */
.industries-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--space-s);
  row-gap: var(--space-m);
  margin-top: var(--space-m);
  width: 100%;
}
.industries-grid li {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  min-width: 0;
}
.industries-grid__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  color: var(--color-iron);
  flex: 0 0 auto;
  margin-bottom: var(--space-s);
}
.industries-grid__icon svg {
  width: 100%;
  height: 100%;
}
.industries-grid__caption {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: 0;
  color: var(--color-iron);
  max-width: none;
  text-wrap: balance;
  /* two-line lock so mixed wraps keep every row's captions on one baseline */
  min-height: calc(var(--text-xs) * 1.25 * 2);
}

/* ==========================================================================
   FOUNDER + CONTACT
   ========================================================================== */
.founder h3, .contact__phone {
  margin-bottom: 0.35rem;
}
.contact__phone a {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  text-decoration: none;
  border-bottom: 1px solid var(--color-brass);
}
.contact__address {
  color: var(--color-iron-soft);
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
footer {
  background-color: var(--color-bone-deep);
  margin-top: var(--space-l);
}
/* Repeated at the SAME size as the hero h1 on purpose (ledger item 9): a
   real plate stamp doesn't shrink between the machine's two tags — it's
   the same die. Deliberately not a scaled-down "afterthought" footer logo. */
/* Sera's mark, same row, immediately left of the wordmark (identity spec's
   footer-only placement — no header/hero instance, no 404 instance). */
.footer__brand {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
  margin-bottom: var(--space-m);
}
/* Fixed 96x32 (3:1) per Sera's spec, no responsive variant given -- without
   flex-shrink:0 a narrow flex row silently squashes the SVG's aspect ratio
   instead of wrapping the wordmark text (caught by measuring rendered
   width/height at 375px, not assumed: 96x32 -> 58x32, a real distortion). */
.footer__brand svg {
  flex-shrink: 0;
}
.footer__wordmark {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-display);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.footer__address { color: var(--color-iron-soft); margin-bottom: var(--space-m); }
/* was `.footer nav …` -- dead, <footer> has no class="footer" (Perta's
   floor-cert finding #2); plain element selector matches the file's own
   existing pattern (see the bare `footer {}` rule above). */
footer nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-m);
  margin-bottom: var(--space-m);
  padding-top: var(--space-m);
  border-top: 1px solid var(--color-hairline);
}
footer nav a {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  text-decoration: none;
  color: var(--color-iron-soft);
}
footer nav a:hover { color: var(--color-iron); }
.footer__copyright {
  font-size: var(--text-xs);
  color: var(--color-iron-soft);
  font-variant-numeric: tabular-nums;
  padding-top: var(--space-m);
}

/* ==========================================================================
   404
   ========================================================================== */
.notfound {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.notfound__code {
  /* tabular-nums only, not mono -- mono stays scoped to the one entity-plate
     block on index.html, site-wide, per the ledger claim */
  font-variant-numeric: tabular-nums;
  color: var(--color-iron-soft);
}
.notfound a {
  display: inline-block;
  margin-top: var(--space-m);
  font-weight: 600;
  border-bottom: 1px solid var(--color-brass);
  text-decoration: none;
}
