/* Flynn Solutions — site brand layer
 *
 * Tokens from brand/tokens.css. Geist is self-hosted rather than pulled from
 * the Google CDN: one less third party, and the render pipeline uses the same
 * file so web, print and social cannot drift onto different cuts.
 *
 * TTF not woff2 because the vendored file is TTF — 165KB against ~55KB. Worth
 * converting before this ships.
 */
@font-face{
  font-family:"Geist";
  /* Subset to Latin, variable wght axis preserved. 165 KB TTF -> 31 KB woff2.
     Rebuild with tools/build_font.sh if the page ever needs a glyph outside Latin. */
  src:url("fonts/Geist.woff2") format("woff2");
  font-weight:100 900;
  font-display:swap;
}

:root{
  --bg:#000000;
  --surface:#1a1c21;
  --border:#383940;
  --text:#f2f6fa;
  --muted:#a2a5a9;
  --dim:#7c7e85;
  --accent:#c1d2ea;
  --l90:#c1d2ea;

  --font: Geist, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --track-wordmark:.19em;

  --gutter:clamp(20px, 5vw, 64px);
  --measure:66ch;
}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{background:var(--bg);color:var(--text);font-family:var(--font);
     font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
::selection{background:var(--accent);color:#00121c}
img{max-width:100%;display:block}
a{color:var(--accent);text-decoration:none}

/* ---------- lockup ---------------------------------------------------------
 * Every value derives from the MARK, never from inherited font-size:
 *   cap ratio 31%   the name's CAP HEIGHT against the mark's height. Cap, not
 *                   font-size -- font-size carries ascender and descender space
 *                   you cannot see, which is why the first attempt read small.
 *   gap 25%         of the mark's width. Lands exactly on the clear-space
 *                   floor, so the lockup's own gap and the minimum anyone else
 *                   must respect are the same number.
 *   tracking .2em   weight 600
 * Geist's cap height is 0.710em, so font-size = mark x 0.31 / 0.710.
 */
.lockup{--mark:34px;display:inline-flex;align-items:center;
  gap:calc(var(--mark) * .25);text-decoration:none}
.lockup img{width:var(--mark);height:var(--mark);flex:none;display:block}
.lockup span{font-size:calc(var(--mark) * .4366);font-weight:600;line-height:1;
  letter-spacing:.2em;text-transform:uppercase;color:var(--l90);white-space:nowrap}
/* Metal wordmark in the lockup. Height derives from the same cap ratio as the
   live-text version -- 0.31 of the mark -- times the render's own 1.0432
   height-per-cap, so swapping between them changes nothing about the layout.

   This render is INK-cropped, not band-cropped like the inline phrases, and the
   two are not interchangeable. .lockup centres with align-items:center, which
   centres the box; a band crop puts the ink of an all-caps word 10.9% of the
   image height below the box centre, landing the wordmark 1.3-1.7px low at real
   lockup sizes. build_metal_text.py picks the crop per job -- don't "unify" them.

   It holds smaller than expected: below ~15px the horizon compresses, but the
   eye stops reading strokes and reads the whole word as one object, so the
   local contrast reads as shine rather than as detail. */
.lockup img.wm{width:auto;height:calc(var(--mark) * .3234);flex:none;display:block}

/* ---------- type scale ---------- */
.kicker{font-size:11px;font-weight:700;letter-spacing:.19em;text-transform:uppercase;
  color:var(--accent)}
h1,h2,h3{font-weight:700;letter-spacing:-.03em;line-height:1.05;text-wrap:balance}
h1{font-size:clamp(38px, 7.2vw, 84px)}
h2{font-size:clamp(28px, 4.4vw, 52px)}
h3{font-size:clamp(18px, 2vw, 23px);letter-spacing:-.02em;line-height:1.25}
.lead{font-size:clamp(16px, 1.6vw, 20px);color:var(--muted);max-width:var(--measure)}
p{color:var(--muted);max-width:var(--measure)}
p+p{margin-top:1em}
.small{font-size:13.5px;color:var(--dim)}

/* ---------- structure ---------- */
.wrap{max-width:1200px;margin:0 auto;padding:0 var(--gutter)}
.rule{height:1px;background:var(--border);border:0}
.accent-rule{height:2px;width:64px;background:var(--accent);border:0}

header.site{position:sticky;top:0;z-index:40;backdrop-filter:blur(14px);
  background:color-mix(in srgb, var(--bg) 88%, transparent);
  border-bottom:1px solid var(--border)}
header.site .inner{display:flex;align-items:center;gap:28px;
  padding:14px var(--gutter);max-width:1200px;margin:0 auto}
header.site nav{display:flex;gap:24px;margin-left:auto}
header.site nav a{font-size:13.5px;color:var(--muted);font-weight:500}
header.site nav a:hover{color:var(--text)}
@media (max-width:860px){header.site nav{display:none}}

footer.site{border-top:1px solid var(--border);margin-top:80px;
  padding:36px var(--gutter);color:var(--dim);font-size:13px}
footer.site .inner{max-width:1200px;margin:0 auto;display:flex;gap:20px;
  align-items:center;flex-wrap:wrap}
footer.site .inner span:last-child{margin-left:auto}

/* ---------- the pull-quote Cory called out ---------- */
.pullquote{border-left:2px solid var(--accent);padding:6px 0 6px 28px;
  max-width:74ch}
.pullquote p{font-size:clamp(18px, 2.2vw, 25px);line-height:1.5;color:var(--text);
  max-width:none;letter-spacing:-.012em}
.pullquote cite{display:block;margin-top:18px;font-style:normal;font-size:13px;
  color:var(--dim);letter-spacing:.04em}

/* ---------- form ---------- */
.field{display:flex;flex-direction:column;gap:7px;margin-bottom:16px}
.field label{font-size:11.5px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--dim)}
.field input,.field textarea{font-family:var(--font);font-size:15px;color:var(--text);
  background:#0a0c0f;border:1px solid var(--border);border-radius:9px;padding:12px 14px}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--accent)}
.field textarea{min-height:118px;resize:vertical;line-height:1.55}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.status{font-size:13.5px;color:var(--muted);min-height:1.4em}
.status.ok{color:#6fc296} .status.err{color:#d98cb0}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ---------------------------------------------------------------- chrome type
 * Metal lettering, built from the MARK'S OWN measured bands: specular #feffff,
 * highlight #d6e6fb, light #b1c3dd, upper-mid #8ea0bc. The horizon sits at its
 * "mid" band lifted to #6b7d96 — the mark's lower-mid and shadow bands measure
 * 2.3:1 and 1.5:1 on black, so a letterform using them would break apart.
 * Worst stop here is 5.0:1.
 *
 * Averaging the logo top-to-bottom does NOT work as a ramp: across an X the
 * highlights and shadows cancel and you get flat grey. The drama is local
 * contrast, so the bands are what to sample, not the mean.
 *
 * Two rules that matter:
 *   - OPT IN via @supports, never opt out. If background-clip:text is missing
 *     and the text is already transparent, the text is invisible. Default to a
 *     solid colour and layer the metal on only where it is supported.
 *   - NO filter/drop-shadow on the element. It forces a new rasterisation
 *     context and breaks background-clip:text in Chromium and Safari — the text
 *     renders solid instead of clipped, which is what "it just looks white"
 *     means. Use a wrapper if a shadow is genuinely needed.
 */
.chrome, .chrome-brushed{
  color:var(--l90);                 /* the visible fallback, always */
}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .chrome, .chrome-brushed{
    -webkit-background-clip:text; background-clip:text;
    -webkit-text-fill-color:transparent; color:transparent;
    padding-bottom:.06em;           /* descenders clip without it */
  }
  .chrome{
    background-image:linear-gradient(180deg,
      #feffff 0%, #d6e6fb 16%, #b1c3dd 38%, #8ea0bc 49%,
      #6b7d96 50%, #8ea0bc 63%, #c8daf2 82%, #eef5ff 100%);
  }
  /* brushed: a 1px grain over the same bands. Reads milled rather than mirror,
     and survives smaller sizes because the grain persists when the ramp
     compresses. */
  .chrome-brushed{
    background-image:
      repeating-linear-gradient(90deg, rgba(255,255,255,.16) 0 1px,
        transparent 1px 2px, rgba(0,0,0,.13) 2px 3px, transparent 3px 5px),
      linear-gradient(180deg,
        #feffff 0%, #d6e6fb 16%, #b1c3dd 38%, #8ea0bc 49%,
        #6b7d96 50%, #8ea0bc 63%, #c8daf2 82%, #eef5ff 100%);
  }
}

/* -------------------------------------------------------- metal type (real)
 * A CSS gradient cannot be metal, for the same reason a gradient SVG cannot be
 * the mark: chrome's colour comes from a surface normal indexing into a matcap,
 * so it varies per pixel. Measured on the render below, one scanline across the
 * letterforms reverses direction 517 times. A linear gradient reverses zero.
 *
 * So the phrase goes through the same pipeline the mark does and ships as a
 * PNG, rendered at 3x. Fixed text, but a hero headline is fixed text. The live
 * text stays in the DOM via alt, so it is still selectable by assistive tech
 * and still indexed.
 *
 * Sizing is measured from BOTH the render and the font, because the two have
 * to agree. The image is 1.378x its own cap height; Geist's cap height is
 * 0.710em. So the image must be 1.378 x 0.710 = 0.979em for its caps to match
 * the surrounding type.
 *
 * The first version used 1.378em directly -- treating a cap-height ratio as if
 * it were an em ratio -- which rendered the phrase 1.41x too large. Ratios are
 * only meaningful against the unit they were measured in.
 */
/* One rule for every metal phrase. The renderer crops to a vertical band taken
 * from the FONT's own metrics, not from the ink, so "shaped" (descender) and
 * "Clean" (none) come back the same height and sit on the same baseline.
 * band = ascent + descent + 0.06em -> 1.9177 bands per cap; 21.75% falls below.
 * The floor is the font's real descent: a guessed 0.10em sheared every 'y' and 'p'. */
.metal-word{
  display:inline-block;
  height:1.3615em;             /* 1.9177 bands-per-cap x 0.710em Geist cap height */
  vertical-align:-0.2962em;    /* 21.75% of the band sits below the baseline */
  width:auto;
}
@media (prefers-reduced-data: reduce){
  .metal-word{display:none}
  .metal-word + .metal-fallback{display:inline}
}
.metal-fallback{display:none;color:var(--l90)}
