/* ============================================================
   system.css - the site's type and surface system.

   Loaded LAST on every page, after each page's inline <style>,
   so it retunes the whole site from one file. The pages keep
   their own layout rules; this file owns typography, tokens,
   radii and the small amount of decoration that survives.

   Replaces the previous Newsreader + Inter + JetBrains Mono
   stack. That pairing carried an editorial-monograph register,
   which reads as a creative-studio signal. The audience here is
   product hiring managers and recruiters who skim first, so the
   register is now a plain professional product site: one family
   doing display and body, with its mono for labels.

   The family is IBM Plex. It was drawn for IBM as a corporate
   face, which is the register this site wants, and it is not one
   of the faces every generated interface converges on. Inter and
   Geist both are, and Geist in particular is now the default of
   the current tooling wave, which is exactly the signal this
   site is trying not to send.
   ============================================================ */

/* ---------- faces ----------
   Self-hosted so the site has no third-party font dependency. */
@font-face{font-family:'Plex';src:url('fonts/IBMPlexSans-Regular.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Plex';src:url('fonts/IBMPlexSans-Medium.woff2') format('woff2');font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:'Plex';src:url('fonts/IBMPlexSans-SemiBold.woff2') format('woff2');font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:'Plex';src:url('fonts/IBMPlexSans-Bold.woff2') format('woff2');font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:'Plex Mono';src:url('fonts/IBMPlexMono-Regular.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Plex Mono';src:url('fonts/IBMPlexMono-Medium.woff2') format('woff2');font-weight:500;font-style:normal;font-display:swap}

/* ---------- tokens ----------
   Both token vocabularies are redefined. The home page uses
   --sans / --serif / --mono, the case studies use --f / --serif
   / --mono. Pointing every display token at the same grotesk is
   what removes the serif from the site in one move. */
:root{
  --sans:'Plex',system-ui,-apple-system,'Segoe UI',sans-serif;
  --f:'Plex',system-ui,-apple-system,'Segoe UI',sans-serif;
  --serif:'Plex',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:'Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

  /* One radius scale. Cards 10, inner elements 6, nothing else. */
  --r:10px;
  --r-sm:6px;

  /* Slightly cooler, slightly deeper ink. The old #14161A sat
     warm against the blue accent. */
  --ink:#101418;   --tx:#101418;
  --ink-2:#474F59;  --tx2:#474F59;
  --ink-3:#5F6771;  --tx3:#5F6771;
  --line:#E2E6EB;   --bd:#E2E6EB;
  --line-2:#C7CDD5;  --bd2:#C7CDD5;
  --accent:#1E3AC4;  --ac:#1E3AC4;
}

body{
  font-family:var(--sans);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  font-feature-settings:"ss02";
  letter-spacing:-0.006em;
}

/* Decoration removed. The film grain was doing nothing the
   hairlines were not already doing, and it cost a fixed
   composite layer on every scroll. */
body::after{display:none!important}

/* ---------- display type ----------
   Sizes come down from the serif settings. A grotesk at 94px
   shouts where a serif at 94px reads as a masthead, so the home
   hero tops out lower and carries its weight in the letterform,
   not the scale. Tracking tightens as size grows. */
h1,h2,h3,h4,.logo,.feat .name,.exp-r,.sh,.st,.about-lead,
.foot-brand h3,.rec blockquote,.context-list span,.feat .imp-n{
  font-family:var(--sans);
  font-variation-settings:normal;
}

h1{
  font-size:clamp(34px,4.8vw,55px)!important;
  font-weight:600!important;
  letter-spacing:-0.025em!important;
  line-height:1.06!important;
  text-wrap:balance;
}
.st,.sh{
  font-weight:600!important;
  letter-spacing:-0.021em!important;
  line-height:1.15!important;
}
.st{font-size:clamp(27px,3.4vw,38px)!important}
.sh{font-size:clamp(20px,2.3vw,25px)!important}

/* Emphasis inside a headline. Carried by colour at the same
   weight, not by italic. The previous system set the emphasised
   words in a serif italic, which is the most copied display move
   on the web right now. */
h1 em,.st em,.sh em,.about-lead em,.hero-p em,.foot-h em{
  font-style:normal;
  font-weight:600;
  color:var(--accent);
}

/* ---------- body type ---------- */
.hero-p,.sd,.sp,.about-col p,.exp-c,.desc,p{
  letter-spacing:-0.004em;
}
.hero-p{font-size:17px!important;line-height:1.6!important}

/* ---------- labels ----------
   Mono, uppercase, wide. These are the only uppercase text on
   the site and they stay small so they read as metadata. */
.sl,.wm,.tg,.mc dt,.imp-l,.exp-d,.context-label,.foot-col h4,
.exp-slot-h,.rec-rel{
  font-family:var(--mono)!important;
  letter-spacing:0.07em!important;
}

/* ---------- numbers ----------
   Every figure on the site is a claim, so figures get tabular
   lining so columns of them line up and read as data. */
.imp-n,.n,.v,.mt .n,.exp-d,.plainmetrics dd,.rec-n{
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum";
}
.imp-n,.mt .n{font-weight:600!important;letter-spacing:-0.015em!important}

/* ---------- surfaces ----------
   One radius everywhere, hairline borders, elevation only on
   hover. No filled panels, no glows. */
.feat,.card,.cd,.tc,.pc,.mc,.rec,.fd,.nda,.wh-item,.exp-slot{
  border-radius:var(--r);
}
.btn,.bk-btn,input,textarea,select{border-radius:var(--r-sm)}

/* ---------- motion ----------
   The dial is low on purpose. A hiring manager scanning on a
   train does not need choreography, and every extra transition
   is one more thing that can stutter. What remains: a single
   reveal on scroll, and small hover feedback. */
@media(prefers-reduced-motion:reduce){
  .rv{opacity:1!important;transform:none!important;filter:none!important}
}

/* ---------- overrides for page-level rules ----------
   The inline stylesheets set these with higher specificity, so
   they are restated here rather than edited in 14 places. */

/* Accent emphasis: colour only, never a synthesised oblique. */
.hero h1 em,.st em,.about-lead em,.cta-card h2 em,.hero-p em{
  font-style:normal!important;
  font-weight:600!important;
  color:var(--accent)!important;
}
.hero-p em,.about-lead em{font-weight:500!important}

/* Two lines of headline, never three. The measure was set for a
   serif, which sets narrower per character than this grotesk. */
.hero h1{max-width:28ch!important;margin-bottom:28px!important}
.hero{padding:104px 0 56px!important}
.cta-card h2{max-width:20ch}

/* Tag and label chips. Mono at this size needs a touch less
   tracking than the section labels or the chips grow too wide. */
.wm,.tg{letter-spacing:0.04em!important;font-size:10.5px!important}

/* ---------- case study contents ----------
   Built by assets/toc.js from the headings already on the page.
   Two columns on desktop so a nine-section case study still reads
   as one glanceable block rather than a long ladder. */
.toc{
  /* The case-study pages style every <nav> as the fixed page header,
     so every one of those properties is reset here. */
  position:static;inset:auto;z-index:auto;height:auto;
  display:block;backdrop-filter:none;border-bottom:0;
  margin:0 0 12px;padding:22px 26px 24px;
  border:1px solid var(--bd);border-radius:var(--r);background:var(--sf);
}
.toc-h{
  font-family:var(--mono);font-size:10.5px;font-weight:500;
  text-transform:uppercase;letter-spacing:0.07em;color:var(--tx3);
  margin:0 0 12px;
}
.toc ol{list-style:none;margin:0;padding:0;columns:2;column-gap:40px}
.toc li{break-inside:avoid;counter-increment:toc}
.toc a{
  display:block;padding:5px 0;font-size:14px;line-height:1.45;
  color:var(--tx2);text-decoration:none;
  border-bottom:1px solid transparent;
  transition:color .18s cubic-bezier(.4,0,.2,1);
}
.toc a::before{
  content:counter(toc,decimal-leading-zero);
  font-family:var(--mono);font-size:10.5px;color:var(--tx3);
  margin-right:10px;
}
.toc a:hover{color:var(--ac)}
.toc a.is-current{color:var(--tx);font-weight:500}
.toc a.is-current::before{color:var(--ac)}
.toc ol{counter-reset:toc}

/* The heading a contents link jumps to must clear the fixed nav. */
.sh{scroll-margin-top:84px}

@media(max-width:768px){
  /* The .w wrapper already pads to the page spine; the old margin here
     inset the contents block a second time. */
  .toc{padding:18px 20px 20px}
  /* Two columns are kept on small screens. a11y.css gives every nav
     link a 44px touch target, and a single column of 13 of those is
     taller than a phone viewport, which defeats the point of a map. */
  .toc ol{columns:2;column-gap:20px}
  .toc a{font-size:13px}
  .toc a::before{margin-right:7px}
}

/* Metric captions. These sit under a large figure, so they stay
   sans and small: a mono caption at this length outweighed the
   number it was describing. */
.mt .l,.metrics .l{
  font-family:var(--sans)!important;
  font-size:11.5px!important;letter-spacing:0!important;
  line-height:1.4!important;color:var(--tx3)!important;
  text-transform:none!important;
}
.nda-t{font-family:var(--sans)!important;letter-spacing:-0.005em!important}

/* ---------- small screens ----------
   The hero padding above is set with !important so it beats the
   page rules, which means the mobile value has to be restated
   here rather than left to the page's own media query. */
@media(max-width:720px){
  .hero{padding:96px 0 40px!important}
  .hero h1{max-width:100%!important}
  /* The mobile nav previously dropped every link and left only the
     CTA, which is a header with no navigation in it. One anchor to
     the work is enough to keep it a nav without a menu button. */
  nav .nr a[href="#work"]{display:inline-flex!important;font-size:14px}
}
@media(max-width:440px){
  nav .nr a[href="#work"]{display:none!important}
}

/* ============================================================
   Corrections from the adversarial review of the first pass.
   Each block names the defect it closes.
   ============================================================ */

/* The contact headline was the one heading still on the old scale:
   56px at weight 500 next to a 55px/600 h1, because it matched none
   of the h1 / .st / .sh selectors above. */
.cta-card h2{
  font-size:clamp(30px,4.2vw,46px)!important;
  font-weight:600!important;
  letter-spacing:-0.023em!important;
  line-height:1.1!important;
  font-variation-settings:normal!important;
}

/* Radius: the surface list above missed the two biggest interactive
   surfaces, so the retired 20px was still on the contact block and
   the two button families had drifted apart at 6px and 10px. */
.cta-card{border-radius:var(--r)!important}
.cta-link,.nr a,.section-head .count,.fn,.img-box img{border-radius:var(--r-sm)!important}

/* Control boundaries need 3:1 under WCAG 1.4.11. --line-2 is 1.51:1,
   which is fine for a decorative rule and not fine for the outline of
   a button, so the buttons get a token of their own. */
:root{--control-bd:#7C838D}
.btn,.cta-link{border-color:var(--control-bd)!important}

/* Labels. The list above missed four label classes that sit inches
   from the ones it caught, leaving two competing label systems on the
   same page. Font size was never set at all, so 9px values survived
   under a system documented as 10.5 to 11px. */
.sl,.wm,.tg,.mc dt,.imp-l,.exp-d,.context-label,.foot-col h3,
.exp-slot-h,.rec-rel,.fd .sv,.pc .rl,.pc dl dt,.wh-item strong,
.eyebrow,.more-h,.more-cat,.am-row dt{
  font-family:var(--mono)!important;
  letter-spacing:0.07em!important;
  font-size:10.5px!important;
}
.tg,.wm{text-transform:uppercase!important}

/* Standing rule, DESIGN.md: a left border above 1px is the tell this
   site avoids. Ten case studies still carried 2px slabs. */
.rolefact,.pc blockquote{border-left-width:1px!important}

/* No italic file is loaded, so this rendered as a browser-slanted
   upright. */
.pc blockquote,.rolefact{font-style:normal!important}

/* Standing rule, DESIGN.md: nothing is centered. The metric tiles are
   the most visible element on a case study. */
.mt,.bk,.img-caption,.metrics .mt{text-align:left!important}

/* ============================================================
   CASE STUDY DETAIL TEMPLATE

   The detail pages were built as a grid of filled grey boxes:
   an eight-cell meta block, a boxed metric strip, and card grids
   at 12.5px inside 14px body copy. Three problems with that.

   The reading size was too small for a page that asks for ten
   minutes. The fill was doing the grouping, so every group
   looked equally important and the page had no hierarchy. And
   the jump from a 55px title to a 24px section heading left the
   sections looking like captions.

   This layer removes the fill, raises the reading size, and
   rebuilds the rhythm on rules and space. Nothing here changes
   the markup, so it applies to all 13 case studies at once.
   ============================================================ */

/* ---------- reading column ---------- */
.case .w{max-width:780px}
.case .sp{
  font-size:16.5px!important;
  line-height:1.68!important;
  color:var(--tx2);
  margin-bottom:18px!important;
}
.case .lead{
  font-size:19px!important;
  line-height:1.6!important;
  color:var(--tx2)!important;
  margin-bottom:40px!important;
}

/* ---------- section rhythm ----------
.case More air between sections than inside them,
.case so the page reads
   as a sequence of arguments rather than a wall. */
hr{margin:72px 0!important}
.case .sl{margin-bottom:10px!important}
.case .sh{margin-bottom:16px!important}

/* ---------- header meta ----------
.case Eight filled tiles became a hairline table. It is the same
   information in a third of the visual weight,
.case and it no longer
   competes with the title above it. */
.mg{
  display:grid!important;
  grid-template-columns:repeat(4,1fr)!important;
  gap:0!important;
  border-top:1px solid var(--bd);
  margin-top:4px;
}
.case .mc{
  background:none!important;
  border:0!important;
  border-bottom:1px solid var(--bd)!important;
  border-radius:0!important;
  padding:14px 20px 14px 0!important;
}
.case .mc dt{margin-bottom:5px!important}
.case .mc dd{font-size:14px!important;font-weight:400!important;line-height:1.45;color:var(--tx)}

/* ---------- outcome figures ----------
.case The boxed strip used a 1px grid gap to fake dividers. Now the
   figures sit on a rule and carry their own weight. */
.metrics{
  background:none!important;
  border:0!important;
  border-top:1px solid var(--bd)!important;
  border-bottom:1px solid var(--bd)!important;
  border-radius:0!important;
  gap:32px!important;
  margin:44px 0!important;
  padding:26px 0!important;
  overflow:visible!important;
}
.case .mt{background:none!important;padding:0!important}
.case .mt .n{font-size:32px!important;line-height:1.05!important}
.case .mt .l{margin-top:6px!important;max-width:22ch}

/* ---------- argument cards ----------
.case Hairline instead of fill. The fill was grouping the content and
   flattening it at the same time: everything in a grey box reads
   as equally weighted. */
.cg{gap:0 28px!important;margin:24px 0 8px!important}
.case .cd{
  background:none!important;
  border:0!important;
  border-top:1px solid var(--bd)!important;
  border-radius:0!important;
  padding:18px 0 22px!important;
}
.case .cd h3{font-size:15px!important;margin-bottom:7px!important;letter-spacing:-0.012em}
.case .cd p{font-size:15px!important;line-height:1.6!important}

/* Finding callouts keep their fill: they are the one component
.case where the colour is carrying meaning rather than decoration. */
.fd{padding:20px 22px!important}
.case .fd h3{font-size:15px!important}
.case .fd p{font-size:14.5px!important;line-height:1.6!important}

/* ---------- comparison columns ---------- */
.case .tc{background:none!important;border:0!important;border-top:1px solid var(--bd)!important;border-radius:0!important;padding:20px 0 0!important}
.case .tc h3{font-size:14px!important;margin-bottom:14px!important}
.case .tg2{gap:0 32px!important}

/* ---------- role cards ---------- */
.case .pc{background:none!important;border:0!important;border-top:1px solid var(--bd)!important;border-radius:0!important;padding:18px 0 20px!important}
.case .wh-item{background:none!important;border:0!important;border-top:1px solid var(--bd)!important;border-radius:0!important;padding:16px 0 18px!important}

/* ---------- confidentiality note ---------- */
.case .nda{background:none!important;border:0!important;border-left:1px solid var(--bd2)!important;border-radius:0!important;padding:4px 0 4px 18px!important}
.case .nda p{font-size:14px!important;line-height:1.6!important}
.case .nda .nda-t{margin-bottom:4px!important}

/* ---------- contents ----------
.case Same move: the filled panel became a ruled block. */
.toc{background:none!important;border:0!important;border-top:1px solid var(--bd)!important;border-bottom:1px solid var(--bd)!important;border-radius:0!important;padding:22px 0 24px!important;margin-bottom:0!important}

@media(max-width:768px){
.case .toc{padding:20px 0 22px!important}
.case .mg{grid-template-columns:1fr 1fr!important}
.case .metrics{gap:24px!important}
.case .sp{font-size:16px!important}
}

/* Tightening pass on the detail template. */

/* The contents block sat under the meta table's closing rule, so two
.case full-width rules framed an empty band. It keeps the lower rule only. */
.toc{border-top:0!important;padding-top:4px!important}

/* Tag chips were the last filled boxes on the page. */
.case .tg{
  background:none!important;
  border:1px solid var(--bd2);
  padding:4px 9px!important;
  color:var(--tx3)!important;
}

/* ---------- roadmap ----------
   A phase sequence for product work. Rules and numbers, no tiles:
   a roadmap drawn as coloured blocks is a picture of a roadmap,
   and what a reader wants is what shipped in what order and why. */
.roadmap{margin:26px 0 8px;border-top:1px solid var(--bd)}
.roadmap-row{
  display:grid;grid-template-columns:132px 1fr;gap:28px;
  padding:20px 0;border-bottom:1px solid var(--bd);
}
.roadmap-when{
  font-family:var(--mono);font-size:10.5px;font-weight:500;
  text-transform:uppercase;letter-spacing:0.07em;color:var(--tx3);
  padding-top:3px;
}
.roadmap-row h3{font-size:15px;font-weight:600;margin-bottom:6px;letter-spacing:-0.012em}
.roadmap-row p{font-size:15px;line-height:1.6;color:var(--tx2)}
.roadmap-row .why{display:block;margin-top:7px;font-size:14px;color:var(--tx3)}
@media(max-width:640px){
  .roadmap-row{grid-template-columns:1fr;gap:6px}
  .roadmap-when{padding-top:0}
}

/* The contents block and the figures below it were each drawing a
   full-width rule with dead space between them. One rule is enough. */
.toc{border-bottom:0!important;padding-bottom:6px!important}

/* ============================================================
   CASE STUDY: WIDE-SCREEN LAYOUT

   A 780px reading column centred on a 1440px screen leaves 330px
   of nothing on each side, which reads as a narrow page floating
   in a wide window rather than as a considered measure.

   Above 1200px the contents block leaves the flow and becomes a
   sticky rail in the left margin. The dead space now does a job,
   the reader can see where they are in a 2,000-word page without
   scrolling back, and the measure stays where it should be for
   reading. Below 1200px it returns to a block under the hero.
   ============================================================ */
@media(min-width:1200px){
  /* Rail 210 + 60 gap + 800 content = 1070, centred. */
  :root{--rail:210px;--gutter:60px;--col:800px}

  .case .w.toc-wrap{
    position:fixed;
    top:104px;
    left:max(28px, calc(50% - 535px));
    width:var(--rail);
    margin:0;padding:0;
    max-height:calc(100vh - 150px);
    overflow-y:auto;
    overscroll-behavior:contain;
  }
  .case .toc{
    border:0!important;padding:0!important;margin:0!important;
    background:none!important;
  }
  .case .toc-h{margin-bottom:14px!important}
  .case .toc ol{columns:1!important}
  .case .toc li{border-left:1px solid var(--bd);padding-left:14px}
  .case .toc a{padding:6px 0!important}
  /* The current section is marked on the rule as well as in the text,
     so position is readable from the edge of the eye. */
  .case .toc li:has(a.is-current){border-left-color:var(--ac);border-left-width:2px;padding-left:13px}

  .case .w:not(.toc-wrap){
    max-width:var(--col);
    margin-left:max(calc(28px + var(--rail) + var(--gutter)), calc(50% - 265px));
    margin-right:0;
  }
  .case .ww{
    max-width:calc(var(--col) + 120px);
    margin-left:max(calc(28px + var(--rail) + var(--gutter)), calc(50% - 265px));
    margin-right:0;
  }
  .case main{padding-bottom:40px}
}

/* Older engines without :has() still get the text mark, just not the rule. */
@supports not selector(:has(*)){
  .case .toc li{border-left-color:var(--bd)}
}
