  :root{
    --paper:#F7F6F3; --panel:#E3E1DA; --ink:#16181D; --muted:#6B6F78; --line:#E1DFD9;
    --accent:#2F5D8C; --accent-dark:#1F4067; --deep:#16233B; --rust:#8A4B2A;
    --serif:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
    --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,"Helvetica Neue",Arial,sans-serif;
    --mono:"SF Mono","IBM Plex Mono",Menlo,Consolas,monospace;
  }
  *,*::before,*::after{box-sizing:border-box}
  html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}
  body{
    margin:0; background:var(--paper); color:var(--ink);
    font-family:var(--sans); font-size:17px; line-height:1.6;
    -webkit-font-smoothing:antialiased;
  }
  .wrap{max-width:1120px; margin:0 auto; padding:0 24px}
  a{color:inherit}
  :focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:2px}
  img{max-width:100%; display:block}

  nav{border-top:2px solid var(--ink); border-bottom:1px solid var(--line); background:var(--paper)}
  nav .row{display:flex; align-items:center; justify-content:space-between; padding:20px 0}
  .brand{
    font-family:var(--serif); font-size:20px; letter-spacing:-.01em;
    text-decoration:none; transition:opacity .15s ease;
  }
  .brand:hover{opacity:.7}
  .navlinks{display:flex; gap:30px; font-size:13px}
  .navlinks a{
    text-decoration:none; color:var(--accent-dark); letter-spacing:.08em; text-transform:uppercase;
    transition:opacity .15s ease;
  }
  .navlinks a:hover{opacity:.7}
  .navlinks .n{color:var(--muted); margin-right:2px}
  @media (max-width:640px){ .navlinks{gap:16px; font-size:11.5px} }

  .secnum{
    display:grid; grid-template-columns:110px 1fr; gap:28px; align-items:start;
  }
  .secnum .num{font-family:var(--serif); font-size:2.6rem; color:#ADA695; line-height:1; font-weight:400}
  .secnum .lbl{
    margin-top:4px; font-size:11.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted);
  }
  .secnum h2{
    font-family:var(--serif); font-weight:400; font-size:clamp(1.7rem,3.2vw,2.3rem);
    margin:0 0 12px; letter-spacing:-.01em; line-height:1.15;
  }
  .secnum .sub{margin:0; max-width:56ch; color:#3B3F47; font-size:16px}
  @media (max-width:640px){
    .secnum{grid-template-columns:1fr}
  }

  header.hero{
    position:relative; overflow:hidden; padding:96px 0 72px;
    border-bottom:1.5px solid var(--line);
  }
  /* The grid lives on a pseudo-element so the fade mask applies to it alone. Masking
     header.hero itself also faded its own text and CTA button on the same gradient, and
     made its border-bottom permanently invisible. inset:0 tracks the padding box, so
     the grid stops short of the border rather than sitting on top of it. */
  header.hero::before{
    content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
    background-image:
      linear-gradient(var(--line) 1px, transparent 1px),
      linear-gradient(90deg, var(--line) 1px, transparent 1px);
    background-size:64px 64px;
    background-position:center top;
    -webkit-mask-image:linear-gradient(to bottom, black 0%, black 55%, transparent 100%);
    mask-image:linear-gradient(to bottom, black 0%, black 55%, transparent 100%);
  }
  header.hero .hero-inner{position:relative; z-index:1}
  .kicker{
    display:flex; align-items:center; gap:10px; margin:0 0 22px;
    font-family:var(--mono); font-size:12px; letter-spacing:.14em; text-transform:uppercase;
    color:var(--accent);
  }
  .kicker .rule{width:28px; height:1px; background:var(--accent)}
  h1.name{
    font-family:var(--serif); font-weight:400; font-size:clamp(3.2rem,10vw,6.4rem);
    line-height:.95; letter-spacing:-.02em; margin:0 0 24px;
  }
  /* Two deliberate lines, no separator. Was a flex row with a hairline .div between the
     clauses, which stranded the hairline at the end of line 1 once the copy grew long
     enough to wrap. Block layout instead, so each clause owns its line at any width. */
  .lede{
    margin:0 0 30px; color:#4A4F59; font-size:17px; max-width:56ch; line-height:1.45;
  }
  .lede span{display:block}
  .lede .l2{color:#2C3039; font-weight:600}
  .pills{display:flex; flex-wrap:wrap; gap:10px; margin:0 0 34px}
  .pill{
    font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--accent-dark);
    border:1px solid var(--line); border-radius:999px; padding:8px 16px; background:var(--paper);
  }
  .btn-cta{
    display:inline-flex; align-items:center; gap:8px; text-decoration:none;
    background:var(--ink); color:#fff; font-size:13px; letter-spacing:.08em; text-transform:uppercase;
    font-weight:600; padding:15px 24px; border-radius:0; transition:background .15s ease;
  }
  .btn-cta:hover{background:var(--accent)}

  section{padding:88px 0; border-bottom:1.5px solid var(--line)}

  .frame{
    position:relative; background:var(--panel); border:1px solid var(--line);
    display:flex; align-items:center; justify-content:center; overflow:hidden;
  }
  .frame img{width:100%; height:100%; object-fit:cover}
  .frame .tag{
    font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
  }
  .frame::before,.frame::after,
  .frame .tick-br::before,.frame .tick-br::after{content:""; position:absolute; width:14px; height:14px}
  .frame::before{top:8px; left:8px; border-top:1px solid var(--muted); border-left:1px solid var(--muted)}
  .frame::after{top:8px; right:8px; border-top:1px solid var(--muted); border-right:1px solid var(--muted)}
  .frame .tick-br{position:absolute; inset:0}
  .frame .tick-br::before{bottom:8px; left:8px; border-bottom:1px solid var(--muted); border-left:1px solid var(--muted)}
  .frame .tick-br::after{bottom:8px; right:8px; border-bottom:1px solid var(--muted); border-right:1px solid var(--muted)}
  /* .fit = never crop the subject; letterbox against the panel instead. */
  .frame.fit img{object-fit:contain; background:var(--panel)}
  /* .fx = nudge the crop when a subject isn't centred in its own source image.
     Set --fx and/or --fy per element; 50% each is the default centre crop. --fy
     matters for a portrait photo in a landscape slot, where the centre band is
     rarely the part worth keeping. */
  .frame.fx img{object-position:var(--fx,50%) var(--fy,50%)}

  .about-grid{margin-top:44px; display:grid; grid-template-columns:260px 1fr; gap:56px}
  .portrait{aspect-ratio:1/1.15}
  /* Photo is 846x1080 (1:1.277), frame is 1:1.15 — object-fit:cover crops ~10% of the
     height. Anchor to the top so that comes off the jacket, not the top of the head. */
  .portrait img{object-position:center top}
  .fig-cap{
    display:flex; justify-content:space-between; margin-top:8px;
    font-family:var(--mono); font-size:11px; color:var(--muted); letter-spacing:.06em;
  }
  .about-body p{margin:0 0 16px; color:#3B3F47; font-size:16.5px}
  .about-body b{color:var(--ink)}
  .facts{margin-top:8px; border-top:1px solid var(--line)}
  .facts .row{
    display:grid; grid-template-columns:150px 1fr; gap:16px; padding:14px 0;
    border-bottom:1px solid var(--line); font-size:15px;
  }
  .facts .row .k{
    font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
    padding-top:2px;
  }
  .stat-strip{
    margin-top:44px; display:grid; grid-template-columns:repeat(4,1fr);
    border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  }
  .stat-strip .stat{padding:20px 0; border-left:1px solid var(--line); padding-left:18px}
  .stat-strip .stat:first-child{border-left:none; padding-left:0}
  .stat-strip .n{font-family:var(--serif); font-size:1.7rem; letter-spacing:-.01em}
  .stat-strip .l{margin-top:6px; font-family:var(--mono); font-size:10.5px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted)}
  @media (max-width:760px){
    .about-grid{grid-template-columns:1fr}
    .portrait{max-width:260px}
    .stat-strip{grid-template-columns:repeat(2,1fr); row-gap:20px}
    .stat-strip .stat:nth-child(3){border-left:none; padding-left:0}
  }

  .proj-grid{margin-top:44px; display:grid; grid-template-columns:repeat(3,1fr); gap:26px}
  .proj-card{display:flex; flex-direction:column}
  .proj-head{display:flex; justify-content:space-between; margin-bottom:12px; font-family:var(--mono); font-size:11.5px; letter-spacing:.08em; text-transform:uppercase}
  .proj-head .tag{color:var(--accent)}
  .proj-head .yr{color:var(--muted)}
  .proj-card .frame{aspect-ratio:4/3; margin-bottom:16px}
  .proj-card h3{font-family:var(--serif); font-weight:400; font-size:1.3rem; margin:0 0 4px; letter-spacing:-.01em; line-height:1.25}
  .proj-role{font-family:var(--mono); font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin:0 0 12px}
  .proj-desc{margin:0 0 18px; font-size:15px; color:#3B3F47; flex:1}
  .proj-link{
    padding-top:14px; border-top:1px solid var(--line); text-decoration:none;
    font-size:13px; letter-spacing:.06em; text-transform:uppercase; font-weight:600; color:var(--accent);
  }
  @media (max-width:860px){ .proj-grid{grid-template-columns:1fr} }

  .resume-card{
    margin-top:44px; background:#fff; border:1px solid var(--line); padding:34px 32px;
    display:flex; align-items:center; justify-content:space-between; gap:24px; flex-wrap:wrap;
  }
  .resume-card h3{font-family:var(--serif); font-weight:400; font-size:1.3rem; margin:0 0 8px}
  .resume-card p{margin:0 0 10px; color:#3B3F47; font-size:15px; max-width:52ch}
  .resume-meta{font-family:var(--mono); font-size:12px; color:var(--muted)}
  .resume-actions{display:flex; gap:10px; flex-shrink:0}
  .btn-dark{
    text-decoration:none; background:var(--ink); color:#fff; font-size:12.5px; letter-spacing:.06em;
    text-transform:uppercase; font-weight:600; padding:13px 20px;
  }
  .btn-outline{
    text-decoration:none; border:1px solid var(--line); color:var(--ink); font-size:12.5px; letter-spacing:.06em;
    text-transform:uppercase; font-weight:600; padding:13px 20px;
  }

  footer.contact{background:var(--deep); color:#EDEFF4; padding:88px 0 0; border-bottom:none}
  footer.contact .secnum .num{color:#445A88}
  footer.contact .secnum .lbl{color:#7C8BAA}
  footer.contact h2{color:#fff}
  footer.contact .sub{color:#B7BECE}
  .contact-grid{
    margin-top:48px; display:grid; grid-template-columns:repeat(3,1fr);
    border-top:1px solid #22304E; border-bottom:1px solid #22304E;
  }
  .contact-grid > div{padding:24px 0; border-left:1px solid #22304E}
  .contact-grid > div:first-child{border-left:none}
  .contact-grid .k{font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:#7C8BAA; margin-bottom:8px}
  .contact-grid .v{font-size:16px}
  .contact-grid a{text-decoration:none; color:#EDEFF4; border-bottom:1px solid #3A4C70}
  .fineprint{
    margin-top:0; padding:22px 0; display:flex; justify-content:space-between; flex-wrap:wrap; gap:8px;
    font-family:var(--mono); font-size:11.5px; letter-spacing:.04em; color:#6B7A99;
  }
  @media (max-width:760px){
    .contact-grid{grid-template-columns:1fr}
    .contact-grid > div{border-left:none; border-top:1px solid #22304E; padding:18px 0}
    .contact-grid > div:first-child{border-top:none}
  }

  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto}
    *{transition:none !important; animation:none !important}
  }

  /* ==================== Case-study pages ==================== */
  /* ---------- Case-study page ---------- */

  .crumb{
    display:inline-flex; align-items:center; gap:8px; text-decoration:none;
    font-family:var(--mono); font-size:11.5px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--accent-dark); margin-bottom:26px;
  }
  .crumb:hover{opacity:.7}

  .cs-hero{padding:52px 0 62px; border-bottom:1.5px solid var(--line)}
  h1.cs-title{
    font-family:var(--serif); font-weight:400; font-size:clamp(2.2rem,5.4vw,3.7rem);
    line-height:1.06; letter-spacing:-.02em; margin:0 0 20px; max-width:22ch;
  }
  .cs-lede{margin:0 0 36px; max-width:64ch; color:#3B3F47; font-size:18px}

  .meta-strip{
    display:grid; grid-template-columns:repeat(4,1fr);
    border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  }
  .meta-strip > div{padding:18px 0 18px 18px; border-left:1px solid var(--line)}
  .meta-strip > div:first-child{border-left:none; padding-left:0}
  .meta-strip .k{
    font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--muted); margin-bottom:7px;
  }
  .meta-strip .v{font-size:15.5px; line-height:1.35}

  /* Figures reuse .frame / .tick-br from styles.css */
  .figure{margin:38px 0}
  .fig-16x10{aspect-ratio:16/10}
  /* .fig-ar = size a frame to its own media rather than to a standard slot, when the
     media is an odd shape and letterboxing it would just add bars. Set it inline the
     same way as --fx: style="--ar:1240/570". */
  .frame.fig-ar{aspect-ratio:var(--ar,16/10)}
  .fig-4x3{aspect-ratio:4/3}
  .fig-pair{display:grid; grid-template-columns:1fr 1fr; gap:24px}
  .fig-pair .figure{margin:0}
  .frame .tag{text-align:center; padding:0 18px; line-height:1.5}

  /* 02 — What I did */
  .steps{margin-top:42px; border-top:1px solid var(--line)}
  .step{
    display:grid; grid-template-columns:54px 1fr; gap:22px;
    padding:21px 0; border-bottom:1px solid var(--line);
  }
  .step .sn{
    font-family:var(--mono); font-size:11px; letter-spacing:.1em; color:var(--accent);
    padding-top:5px;
  }
  .step p{margin:0; color:#3B3F47; font-size:16px; max-width:72ch}

  /* 03 — Tools & methods reuses .facts from styles.css */

  /* 04 — What went wrong. Still the most important section on Projects 01 and 02, but
     the weight now comes entirely from the rust rule on each failure block. It used to
     also carry a white ground and deeper padding (104px vs the standard 88px); Rowan
     removed both, so the section sits on --paper like every other section. Don't
     reintroduce the white ground. */
  .fail-list{margin-top:46px}
  .failure{border-left:3px solid var(--rust); padding:2px 0 2px 26px; margin:0 0 42px}
  .f-head{
    display:flex; gap:14px; flex-wrap:wrap; margin-bottom:11px;
    font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  }
  .f-n{color:var(--rust)}
  .f-where{color:var(--muted)}
  .failure h3{
    font-family:var(--serif); font-weight:400; font-size:1.42rem; line-height:1.22;
    letter-spacing:-.01em; margin:0 0 13px;
  }
  .failure p{margin:0 0 14px; color:#3B3F47; font-size:16.5px; max-width:72ch}
  .f-fix{margin-top:17px; padding-top:15px; border-top:1px solid var(--line)}
  .f-fix .lbl{
    display:block; margin-bottom:9px; font-family:var(--mono); font-size:10.5px;
    letter-spacing:.12em; text-transform:uppercase; color:var(--rust);
  }
  .f-fix p:last-child{margin-bottom:0}
  .f-note{
    display:inline-block; margin-top:2px; font-family:var(--mono); font-size:11px;
    letter-spacing:.04em; color:var(--muted);
  }
  /* The one thing that was checked and passed — deliberately not dressed as a failure. */

  /* 05 — What I learned */
  .learn-list{margin-top:40px; border-top:1px solid var(--line)}
  .learn{
    display:grid; grid-template-columns:54px 1fr; gap:22px;
    padding:26px 0; border-bottom:1px solid var(--line);
  }
  .learn .ln{
    font-family:var(--mono); font-size:11px; letter-spacing:.1em; color:var(--accent);
    padding-top:8px;
  }
  .learn p{
    margin:0; font-family:var(--serif); font-size:1.16rem; line-height:1.5;
    color:var(--ink); max-width:64ch;
  }

  /* 06 — Next steps */
  .next-list{margin-top:40px; border-top:1px solid var(--line)}
  .next-item{
    display:grid; grid-template-columns:24px 1fr; gap:14px; align-items:start;
    padding:14px 0; border-bottom:1px solid var(--line); color:#3B3F47; font-size:16px;
  }
  .next-item .mk{font-family:var(--mono); font-size:12px; color:var(--accent); padding-top:3px}
  .next-phase{
    margin-top:26px; font-family:var(--mono); font-size:11px; letter-spacing:.1em;
    text-transform:uppercase; color:var(--muted);
  }

  .cs-footnav{padding:34px 0; display:flex; justify-content:space-between; gap:18px; flex-wrap:wrap}
  .cs-footnav a{
    text-decoration:none; font-family:var(--mono); font-size:12px; letter-spacing:.08em;
    text-transform:uppercase; color:var(--accent-dark);
  }
  .cs-footnav a:hover{opacity:.7}

  @media (max-width:860px){
    .meta-strip{grid-template-columns:repeat(2,1fr)}
    .meta-strip > div:nth-child(3){border-left:none; padding-left:0}
    .meta-strip > div:nth-child(3),.meta-strip > div:nth-child(4){border-top:1px solid var(--line)}
  }
  @media (max-width:760px){
    .fig-pair{grid-template-columns:1fr}
    .step,.learn{grid-template-columns:1fr; gap:8px}
    .step .sn,.learn .ln{padding-top:0}
  }

  /* .white = figures whose source art is on a white ground; letterbox seamlessly. */
  .frame.white,.frame.white img{background:#fff}
  /* .fig-narrow = cap the display width of low-resolution source figures so they
     aren't upscaled past roughly their native pixel size. */
  .fig-narrow{max-width:560px}

  /* Video figures reuse the .frame treatment — same corner ticks, same aspect ratios,
     same .fit behaviour. Project 03's drop test and launch clips are the first use. */
  .frame video{width:100%; height:100%; object-fit:cover; display:block}
  .frame.fit video{object-fit:contain}
