/* ==========================================================================
   Go!Gosling — "Plate & Press" furniture  (design direction D1, 2026-09-22)

   Same furniture as kairwang.cloud, gogosling's own stock. Nothing in this
   file changes the material: white paper, the sky-blue accent, the 18px card
   radius and all twelve Gosli illustrations are untouched. What it adds is
   the shared layer the two sites are recognised by in the first 300 ms —
   grid, rules, label typesetting, numerals:

     1. monospace label stamps        .eyebrow, .apply-dialog__eyebrow, .step__num
     2. hairline section rules        .sec-head::before (ink-bleed at both ends)
     3. 2px square chips              .chip, .job-card__tag, .store-badge__tag
     4. a drawing-sheet title block   .plate-tb (site / sheet / rev / drawn by)
     5. corner registration marks     .plate-reg

   D1's hard rule is that every new piece of furniture binds to a real field;
   anything that would only point at the design itself was left out. That is
   why there are no invented section numbers (no page carries a running index
   — the only real ordinals are how.html's three steps and the numbers already
   written into the legal headings) and no "SCALE 1:1"-class annotation.

   Loaded after site.css and before mobile.css. Nothing here is !important:
   mobile.css still wins at its breakpoints.
   ========================================================================== */

/* --- The one webfont on this site ---------------------------------------- */
/* gogosling ships zero third-party resources by positioning, and that does not
   change: this face is SELF-HOSTED from assets/fonts/, byte-identical to the
   slice kairwang.cloud already serves (sha256 01d28544…), and no Google domain
   is contacted. The two domains removed from the CSP on 2026-08-24 stay
   removed — see snippets/gogosling-headers.conf, which still says font-src
   'self' and needs no edit for this.
   One weight, one script: IBM Plex Mono 500, Latin slice only, 14,888 bytes.
   Everything it is used for is Latin (stamps, numerals, the title block's
   values); the translated labels fall through the stack below to the system
   monospace for CJK, which is the intended behaviour, not a gap. */
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* The fallback is a real stack, not a bare `monospace`: with font-display
     swap the first paint uses it, so it has to be a metric-plausible mono on
     every platform, and it has to carry CJK for the translated stamp labels. */
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
               Consolas, "PingFang SC", "Microsoft YaHei", monospace;

  /* Rule ink. Deliberately between --line (0.06) and --line-strong (0.10):
     a rule that fades at both ends needs a slightly stronger middle to read
     as one line. Every rule drawn with it is aria-hidden decoration and
     carries no information, so it is exempt from the 4.5:1 text minimum —
     same footing as the existing --line hairlines. */
  --plate-rule: rgba(0, 0, 0, 0.16);
  --plate-reg-ink: rgba(0, 0, 0, 0.16);
}

/* --- 1. Label stamps ------------------------------------------------------ */
/* The eyebrow was 15px semibold sentence case — i.e. a small heading. As a
   stamp it stops competing with the section title underneath it and starts
   reading as a field label, which is what it has always actually been. */
.eyebrow,
.apply-dialog__eyebrow {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.75rem;                       /* 12px */
  line-height: 1.4;
  letter-spacing: var(--tracking-eyebrow);  /* 0.14em, a token that existed unused */
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
/* The trailing letter-space of the last glyph pushes a centred stamp half a
   space off centre; pull it back so it sits on the same axis as the title. */
.sec-head.center .eyebrow { margin-right: calc(-1 * var(--tracking-eyebrow)); }

/* how.html's three steps are the only real running ordinal on the site, so
   they are the only numerals that get the plate treatment. The leading zero is
   generated, not written into the markup: the element is aria-hidden, so this
   adds a typographic form, not a fact a screen reader has to read out. */
.steps--plain .step__num {
  font-family: var(--font-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  border-radius: 2px;
  /* The badge is display:grid in site.css, which makes the ::before a grid
     ITEM: it lands in its own cell and "01" comes out as a stacked (or gapped)
     pair. Back to a block with a line-height equal to the badge height, so the
     leading zero is what it should be — an inline glyph in the same run. */
  display: block;
  line-height: 2.5rem;
  text-align: center;
}
.steps--plain .step__num::before { content: "0"; }

/* --- 2. Hairline section rules, ink-bleed ends ---------------------------- */
/* A real blueprint line is thin at its ends where the ink bleeds out; a flat
   1px border from edge to edge is the screen default. Drawn on a ::before, not
   as a background on the section, on purpose: on kairwang the equivalent rule
   lives in the section's own background and any later `background:` shorthand
   silently eats it. A pseudo-element cannot be eaten that way. */
.sec-head { position: relative; }
.sec-head::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: calc(-1 * var(--space-6));
  height: 1px;
  background: linear-gradient(
    90deg,
    rgba(0, 0, 0, 0) 0%,
    var(--plate-rule) 7%,
    var(--plate-rule) 93%,
    rgba(0, 0, 0, 0) 100%
  );
}
/* Not above a page's first heading: a rule there reads as a stray underline of
   the navigation, not as the start of a section. */
.subhero .sec-head::before { content: none; }

/* --- 3. Square chips ------------------------------------------------------ */
/* 999px pills are the single most generic shape on the modern web. 2px is the
   corner a trimmed, printed label actually has. Size, padding and colour are
   untouched — only the corner changes. */
.chip,
.job-card__tag,
.store-badge__tag { border-radius: 2px; }

/* --- 4. Title block ------------------------------------------------------- */
/* A drawing sheet ends in a title block, and every cell in a real one holds a
   field. These four do: the host it was served from, the sheet id (<body
   data-page>, the same attribute the navigation reads for aria-current), the
   revision it was drawn at, and who drew it. It is left in the accessibility
   tree deliberately — it is a colophon, not ornament. */
.plate-tb {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--line);
  border-radius: 2px;
  margin-top: var(--space-6);
  overflow: hidden;
  background: var(--surface);
}
.plate-tb__cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px var(--space-4);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
  min-width: 0;
}
.plate-tb__cell:nth-child(-n + 2) { border-top: 0; }
.plate-tb__cell:nth-child(odd) { border-left: 0; }
.plate-tb__k {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.625rem;              /* 10px — a field label, never read as copy */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.plate-tb__v {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-chip);        /* 13px */
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
@media (min-width: 720px) {
  .plate-tb { grid-template-columns: repeat(4, 1fr); }
  .plate-tb__cell:nth-child(-n + 4) { border-top: 0; }
  .plate-tb__cell:nth-child(odd) { border-left: 1px solid var(--line); }
  .plate-tb__cell:first-child { border-left: 0; }
}

/* --- 5. Corner registration marks ----------------------------------------- */
/* Two plates align here. It is the one mark in this file with no field behind
   it, which is exactly why it appears FOUR times on a page and never a fifth:
   a registration target that turns up on a card would be a lie.

   Fixed, because the sheet you are aligning is the one you are looking at —
   but inset to the corners of the SHEET, not the window: the fixed navigation
   (64px, z-index 100) would otherwise cover the top pair as soon as it gains
   a background on scroll, and the cookie banner the bottom pair. The bottom
   offset reads --cookie-banner-h, which cookies.js already measures and keeps
   in sync on resize, so the marks move up while the banner is open and settle
   back when it is dismissed.

   Shown from 1240px only: that is the first width at which the 1140px content
   container leaves a 50px gutter, i.e. the first width at which a corner mark
   is in the margin rather than on top of the copy. */
.plate-reg { display: none; }
@media (min-width: 1240px) {
  .plate-reg {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
  }
  .plate-reg i {
    position: absolute;
    width: 13px;
    height: 13px;
    border: 1px solid var(--plate-reg-ink);
    border-radius: 50%;
  }
  .plate-reg i::before,
  .plate-reg i::after {
    content: "";
    position: absolute;
    background: var(--plate-reg-ink);
  }
  /* Arms overshoot the ring by 4px on each side, with the centre left open —
     the crosshair of a register mark, not a plus sign. */
  .plate-reg i::before { left: -5px; right: -5px; top: 50%; height: 1px; }
  .plate-reg i::after { top: -5px; bottom: -5px; left: 50%; width: 1px; }
  .plate-reg {
    --_gap: 20px;
    --_top: calc(var(--nav-h) + var(--_gap));
    --_bottom: calc(var(--_gap) + var(--cookie-banner-h, 0px));
  }
  .plate-reg i:nth-child(1) { top: var(--_top); left: var(--_gap); }
  .plate-reg i:nth-child(2) { top: var(--_top); right: var(--_gap); }
  .plate-reg i:nth-child(3) { bottom: var(--_bottom); left: var(--_gap); }
  .plate-reg i:nth-child(4) { bottom: var(--_bottom); right: var(--_gap); }
}

/* --- 6. Gosli, two very small movements ----------------------------------- */
/* The twelve state illustrations are the strongest brand asset on this site
   (2026-08-25 audit), so they get acknowledgement, not choreography: the sheet
   lifts 1px and the drawing inside it rises 2px — the card behaves like paper
   picked up at one corner. No glow, no scale, no shadow bloom. 180 ms is under
   the threshold where a hover reads as an animation rather than a response. */
@media (hover: hover) {
  .state-tile {
    transition: transform 180ms var(--ease-standard),
                border-color 180ms var(--ease-standard);
  }
  .state-tile__media img { transition: transform 180ms var(--ease-standard); }
  .state-tile:hover,
  .state-tile:focus-within {
    transform: translateY(-1px);
    border-color: var(--line-strong);
  }
  .state-tile:hover .state-tile__media img,
  .state-tile:focus-within .state-tile__media img { transform: translateY(-2px); }
}

/* 404: Gosli is asleep on that page. A 4-second 0.92↔1 fade is slow enough and
   shallow enough that it is not seen so much as noticed — the drawing is
   breathing, which is the one thing a sleeping character must do. It is the
   only element on the page that moves. */
@keyframes plate-breathe {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.92; }
}
.nf__art { animation: plate-breathe 4s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .state-tile,
  .state-tile__media img { transition: none; }
  .state-tile:hover,
  .state-tile:focus-within { transform: none; }
  .state-tile:hover .state-tile__media img,
  .state-tile:focus-within .state-tile__media img { transform: none; }
  .nf__art { animation: none; }
}

/* --- Print ---------------------------------------------------------------- */
/* Gradients are dropped by most print pipelines, so every generated rule goes
   back to a real border on paper. The registration marks are the one thing
   that is MORE meaningful printed, so they stay. */
@media print {
  .sec-head::before {
    background: none;
    border-top: 1px solid #000;
    height: 0;
  }
  .plate-tb,
  .plate-tb__cell { border-color: #000; }
  .plate-reg i { border-color: #000; }
  .plate-reg i::before,
  .plate-reg i::after { background: #000; }
  .nf__art { animation: none; }
}
