/* ==========================================================================
   Stuart Ford — Paper & Navy
   Type: Schibsted Grotesk throughout. Scale and spacing both run on one
   modular rhythm so sections relate rather than just stack.
   ========================================================================== */

/* --- 1. Reset ------------------------------------------------------------ */
*,*::before,*::after{box-sizing:border-box}
*{margin:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
img,svg,video{display:block;max-width:100%;height:auto}
button,input,select,textarea{font:inherit;color:inherit}
a{color:inherit}
h1,h2,h3,h4{font-weight:inherit;text-wrap:balance}
p,li{text-wrap:pretty}

/* --- 2. Tokens ----------------------------------------------------------- */
:root{
  /* Dark ground, lifted surfaces. Depth comes from how far a surface sits
     above the page, not from hue — champagne is the only colour in the set. */
  --paper:#0E0C0B;      /* page ground      — bone 17.4:1 */
  --paper-2:#151210;    /* recessed tint */
  --card:#1A1613;       /* lifted surface   — bone 15.9:1 */
  --ink:#F3F1EC;
  --muted:#A9A297;      /* 7.9:1 on paper, 7.2:1 on card */
  --navy:#C8A87C;       /* champagne accent — 9.1:1 on paper, AAA */
  --navy-deep:#0A0908;  /* the deepest ground */
  --navy-soft:#1F1A16;
  --plate-ink:#F3F1EC;
  --plate-muted:#A9A297;
  --plate-acc:#C8A87C;
  --line:rgba(243,241,236,.10);
  --line-int:#6E675E;   /* 4.2:1 */
  --on-accent:#16130F;  /* ink, for use on champagne */
  /* Lift: a hairline of light on the top edge, and a deep soft shadow under */
  --lift-edge:inset 0 1px 0 rgba(243,241,236,.06);
  --shadow-1:0 1px 2px rgba(0,0,0,.35);
  --shadow-2:0 1px 2px rgba(0,0,0,.4),0 28px 60px -28px rgba(0,0,0,.85);

  --sans:"Schibsted Grotesk",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --ease:cubic-bezier(.2,.7,.3,1);

  /* Type scale — one ratio, used everywhere */
  --t-display:clamp(2.9rem,7.4vw,6.1rem);
  --t-h1:clamp(2.2rem,5vw,3.9rem);
  --t-h2:clamp(1.6rem,3vw,2.5rem);
  --t-h3:clamp(1.18rem,1.8vw,1.5rem);
  --t-lead:clamp(1.08rem,1.5vw,1.32rem);
  --t-body:1.0625rem;
  --t-sm:.94rem;
  --t-xs:.84rem;
  --t-label:.78rem;

  /* Spacing rhythm — every gap on the site comes from this scale */
  --s1:.5rem; --s2:.75rem; --s3:1rem; --s4:1.5rem;
  --s5:2rem;  --s6:3rem;   --s7:4rem; --s8:6rem;

  --pad:clamp(1.15rem,4vw,3.5rem);
  --maxw:1180px;
  --measure:68ch;

  /* Section rhythm — three weights, so importance reads as air */
  --sec-lg:clamp(4.5rem,11vw,8.5rem);   /* hero */
  --sec-md:clamp(3.5rem,8vw,6rem);      /* primary sections */
  --sec-sm:clamp(2.5rem,5.5vw,4rem);    /* supporting sections */

  color-scheme:dark;
}


/* --- 3. Base ------------------------------------------------------------- */
body{background:var(--paper);color:var(--ink);font-family:var(--sans);
     font-size:var(--t-body);line-height:1.6}
::selection{background:var(--navy);color:var(--paper)}
:focus-visible{outline:2px solid var(--navy);outline-offset:3px;border-radius:3px}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad)}
.measure{max-width:var(--measure)}

/* --- 4. Type primitives -------------------------------------------------- */
.label{font-size:var(--t-label);font-weight:600;letter-spacing:.01em;color:var(--muted)}
.display{font-weight:700;letter-spacing:-.034em;line-height:1.02}
.lead{font-size:var(--t-lead);line-height:1.58;color:var(--muted);letter-spacing:-.008em}

.prose>*+*{margin-top:var(--s3)}
.prose h2{font-size:var(--t-h2);font-weight:700;letter-spacing:-.032em;line-height:1.08;margin-top:var(--s7)}
.prose h3{font-size:var(--t-h3);font-weight:700;letter-spacing:-.018em;margin-top:var(--s5)}
.prose p,.prose li{color:var(--muted)}
.prose strong{color:var(--ink);font-weight:600}
.prose ul,.prose ol{padding-left:1.15em}
.prose li+li{margin-top:.4em}
.prose a{color:var(--ink);text-decoration:none;
  background-image:linear-gradient(currentColor,currentColor);background-size:0 1px;
  background-repeat:no-repeat;background-position:0 100%;
  box-shadow:inset 0 -1px 0 var(--line-int);transition:background-size .3s var(--ease)}
.prose a:hover{background-size:100% 1px;color:var(--navy)}

/* --- 5. Identity line -----------------------------------------------------
   No sticky chrome. The name sits in the body; on a case study it doubles as
   the way back to the index. */
.ident{padding-block:clamp(1.5rem,3vw,2.25rem) 0}
.ident__name,.ident__back{display:inline-flex;align-items:center;gap:.5rem;
  font-weight:700;font-size:1.02rem;letter-spacing:-.022em;text-decoration:none;color:var(--ink)}
.ident__name span,.ident__back span{color:var(--muted);font-weight:400}
.ident__back svg{width:16px;height:16px;color:var(--navy);transition:transform .3s var(--ease)}
.ident__back:hover svg{transform:translateX(-3px)}
.ident__back:hover span{color:var(--ink)}

/* --- 6. Hero — the widest scale range on the site ------------------------ */
.hero{padding-block:var(--sec-lg) var(--sec-md)}
.hero__kicker{display:flex;align-items:center;gap:var(--s2);margin-bottom:clamp(1.5rem,3vw,2.25rem);
  font-size:var(--t-label);font-weight:600;color:var(--muted)}
.hero__kicker .dot{width:26px;height:1px;background:var(--line-int);border-radius:0;flex:none}
.hero__grid{display:grid;gap:clamp(1.75rem,4vw,3.5rem)}
@media(min-width:960px){.hero__grid{grid-template-columns:minmax(0,7fr) minmax(0,4fr);align-items:end}}
.hero h1{font-size:var(--t-display);font-weight:700;line-height:.98;letter-spacing:-.042em;margin-left:-.055em}
.hero h1 em{font-style:normal;color:var(--navy)}
.hero__sub{padding-bottom:.4rem}
.hero__sub .lead{max-width:42ch}

/* Bento — four equal tiles. The feature is marked by ground colour, not size. */
.hero__meta{margin-top:clamp(2.5rem,5vw,var(--s7));display:grid;gap:var(--s2);
  grid-template-columns:1fr}
.hero__meta>div{background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:clamp(1.15rem,2.2vw,1.5rem) clamp(1.15rem,2vw,1.6rem);
  transition:border-color .3s var(--ease)}
.hero__meta>div:hover{border-color:var(--line-int)}
@media(min-width:620px){.hero__meta{grid-template-columns:repeat(2,1fr)}}
@media(min-width:1000px){.hero__meta{grid-template-columns:repeat(4,1fr)}}
/* The feature tile is marked by ground, not by size */
.hero__meta>div:nth-child(2){background:var(--navy-soft);border-color:transparent}
.hero__meta dt{font-size:var(--t-label);font-weight:600;color:var(--navy);margin-bottom:.5rem}
.hero__meta dd{margin:0;font-size:1.04rem;font-weight:700;letter-spacing:-.018em;line-height:1.25}
.hero__meta dd small{display:block;font-weight:400;font-size:var(--t-xs);color:var(--muted);
  margin-top:.4rem;line-height:1.5;letter-spacing:0}

/* --- 7. Sections --------------------------------------------------------- */
.section{padding-block:var(--sec-md)}
.section--sm{padding-block:var(--sec-sm)}
.section--tint{background:var(--paper-2)}
.section__head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);flex-wrap:wrap;
  padding-bottom:var(--s3);border-bottom:1px solid var(--line);margin-bottom:clamp(2rem,4vw,var(--s6));position:relative}
.section__head::after{content:"";position:absolute;left:0;bottom:-1px;width:38px;height:2px;background:var(--navy)}
.section__head h2{font-size:clamp(1.35rem,2.3vw,1.85rem);font-weight:700;letter-spacing:-.028em}

/* --- 8. Work cards — one large card per row ------------------------------ */
.work-list{display:grid;gap:clamp(1.25rem,2.5vw,1.75rem)}
.work-card{display:grid;gap:clamp(1.75rem,4vw,3.25rem);text-decoration:none;color:inherit;
  padding:clamp(1.75rem,3.6vw,var(--s6));border:1px solid var(--line);border-radius:16px;
  background:var(--card);position:relative;
  transition:border-color .35s var(--ease),transform .35s var(--ease),box-shadow .35s var(--ease)}
@media(min-width:960px){.work-card{grid-template-columns:minmax(0,1fr) minmax(0,1.08fr);align-items:center}}
.work-card:hover{border-color:var(--line-int);transform:translateY(-3px);box-shadow:var(--shadow-2)}
.work-card__num{display:block;font-size:var(--t-label);font-weight:600;color:var(--navy)}
.work-card h3{font-size:clamp(1.75rem,3.4vw,2.7rem);font-weight:700;letter-spacing:-.036em;line-height:1.02;
  margin:.85rem 0 0;max-width:19ch;transition:color .25s var(--ease)}
.work-card:hover h3{color:var(--navy)}
.work-card__desc{margin-top:var(--s3);color:var(--muted);max-width:46ch;font-size:.99rem}
.work-card__stats{margin-top:clamp(1.25rem,2.5vw,1.6rem);padding-top:var(--s3);border-top:1px solid var(--line);
  display:flex;flex-wrap:wrap;gap:var(--s4) var(--s5)}
.stat__val{display:block;font-size:clamp(1.35rem,2.2vw,1.75rem);font-weight:700;letter-spacing:-.032em;
  line-height:1;font-variant-numeric:tabular-nums}
.stat__key{display:block;margin-top:.45rem;font-size:var(--t-xs);color:var(--muted);line-height:1.45;max-width:22ch}
.work-card__more{margin-top:clamp(1.25rem,2.5vw,1.6rem);display:inline-flex;align-items:center;gap:.45rem;
  font-size:var(--t-sm);font-weight:600;color:var(--navy)}
.work-card__more svg{width:15px;height:15px;transition:transform .3s var(--ease)}
.work-card:hover .work-card__more svg{transform:translateX(4px)}
.work-card__vis{position:relative;aspect-ratio:4/3;border-radius:11px;overflow:hidden;
  background:var(--paper-2);border:1px solid var(--line);display:grid;place-items:center}
/* Absolute so the image fills the aspect-ratio box exactly. With place-items:center
   a height:100% image resolves against the grid area instead and overflows. */
.work-card__vis img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .55s var(--ease)}
.work-card:hover .work-card__vis img{transform:scale(1.02)}
.work-card__vis .placeholder{font-size:var(--t-xs);font-weight:600;color:var(--muted);text-align:center;line-height:1.7}

/* --- 9. Navy band — the accent gets a field of its own ------------------- */
.band{background:var(--navy-deep);color:var(--plate-ink);border-radius:16px;padding-block:var(--sec-md);margin-block:var(--sec-md)}
.band h2{font-size:var(--t-h2);font-weight:700;letter-spacing:-.032em;line-height:1.06;max-width:20ch;margin-bottom:var(--s3)}
.band p{color:var(--plate-muted);max-width:56ch}
.band .band__stats{margin-top:clamp(2rem,4vw,var(--s6));display:grid;gap:var(--s5);
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.band .band__stats div{border-top:2px solid var(--plate-acc);padding-top:var(--s3)}
.band .band__stats b{display:block;font-size:clamp(2rem,3.6vw,2.9rem);font-weight:700;letter-spacing:-.04em;
  line-height:1;font-variant-numeric:tabular-nums;color:var(--plate-acc)}
.band .band__stats span{display:block;margin-top:.55rem;font-size:var(--t-xs);color:var(--plate-muted);line-height:1.45}

/* --- 10. Also / proof ---------------------------------------------------- */
.also{margin-top:clamp(2rem,4vw,var(--s6));padding-top:var(--s4);border-top:1px solid var(--line);max-width:64ch}
.also .label{display:block;margin-bottom:var(--s2)}
.also h3{font-size:var(--t-h3);font-weight:700;letter-spacing:-.018em;margin-bottom:var(--s1)}
.also p{color:var(--muted);font-size:var(--t-sm);line-height:1.6}
.also a{color:var(--navy);text-decoration:none;font-weight:600;white-space:nowrap}
.also a:hover{text-decoration:underline;text-underline-offset:3px}

.proof{display:grid;gap:clamp(1.75rem,3vw,var(--s5));grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.proof__item{padding-top:var(--s3);border-top:2px solid var(--ink)}
.proof__item h3{font-size:var(--t-h3);font-weight:700;letter-spacing:-.018em;margin-bottom:var(--s1)}
.proof__item p{color:var(--muted);font-size:var(--t-sm);line-height:1.6}

/* --- 11. Case study ------------------------------------------------------ */
.case-head{padding-block:clamp(3rem,7vw,5.5rem) var(--s6)}
.case-head .label{display:block;margin-bottom:var(--s3)}
.case-head h1{font-size:var(--t-h1);font-weight:700;letter-spacing:-.038em;line-height:1.02;max-width:18ch;margin-left:-.04em}
.case-head .lead{margin-top:var(--s4);max-width:58ch}

/* Outcome strip — metrics and contribution above the fold, on purpose */
.case-topline{margin-top:clamp(2rem,4vw,var(--s6));padding:var(--s4) 0;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
.case-topline dt{font-size:var(--t-label);font-weight:600;color:var(--muted);margin-bottom:.35rem}
.case-topline dd{margin:0;font-size:1.02rem;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.case-topline dd small{display:block;font-weight:400;font-size:var(--t-xs);color:var(--muted);margin-top:.2rem;letter-spacing:0}

.case-facts{margin-top:var(--s4);display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.case-facts dt{font-size:var(--t-label);font-weight:600;color:var(--muted);margin-bottom:.3rem}
.case-facts dd{margin:0;font-size:var(--t-sm);font-weight:600}

.case-body{display:grid;gap:var(--s4);align-items:start}
@media(min-width:1000px){.case-body{grid-template-columns:210px minmax(0,1fr);gap:clamp(2rem,5vw,var(--s7))}}
.case-toc{display:none}
@media(min-width:1000px){
  .case-toc{display:block;position:sticky;top:32px}
  .case-toc ol{list-style:none;padding:0;display:grid;gap:.55rem}
  .case-toc a{text-decoration:none;font-size:var(--t-sm);color:var(--muted);display:block;
    padding-left:.85rem;border-left:2px solid var(--line);transition:color .2s,border-color .2s}
  .case-toc a:hover{color:var(--ink)}
  .case-toc a.is-active{color:var(--ink);border-color:var(--navy)}
}
.case-section{scroll-margin-top:32px}
.case-section+.case-section{margin-top:var(--sec-md)}
.case-section>.label{display:block;margin-bottom:var(--s2)}
.case-section>h2{font-size:var(--t-h2);font-weight:700;letter-spacing:-.032em;line-height:1.08;
  margin-bottom:var(--s3);max-width:24ch}

figure{margin:clamp(2rem,4vw,var(--s6)) 0}
figure img{border-radius:11px;border:1px solid var(--line);width:100%}
figcaption{margin-top:var(--s2);font-size:var(--t-xs);color:var(--muted);max-width:62ch;line-height:1.55}
figcaption b{color:var(--ink);font-weight:600}
.fig-frame{border:1px solid var(--line);border-radius:11px;background:var(--paper-2);
  aspect-ratio:16/10;display:grid;place-items:center}
.fig-frame .placeholder{font-size:var(--t-xs);font-weight:600;color:var(--muted);text-align:center;
  padding:var(--s4);max-width:40ch;line-height:1.7}

/* Exploration — the highest-scoring section, so it gets real presence */
/* Weighted by outcome: the explorations that were left behind sit small and
   in a row; what shipped takes the full width underneath. Size carries the
   verdict, so the chips are gone. */
.explore{display:grid;gap:var(--s3);grid-template-columns:1fr;
  margin:clamp(2rem,4vw,var(--s6)) 0}
@media(min-width:760px){
  .explore{grid-template-columns:repeat(6,1fr)}
  .explore__item{grid-column:span 2}
  .explore__item[data-verdict="shipped"]{grid-column:span 4;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);
    display:grid;align-items:center;gap:0}
  .explore__item[data-verdict="shipped"] .explore__vis{aspect-ratio:16/10;border-bottom:0;border-right:1px solid var(--line);height:100%}
  .explore__item[data-verdict="shipped"] .explore__txt{padding:clamp(1.5rem,3vw,2.25rem)}
  .explore__item[data-verdict="shipped"] h4{font-size:var(--t-h3)}
  /* With four or more explorations the outcome takes a full row instead */
  .explore:has(> :nth-child(4)) .explore__item[data-verdict="shipped"]{grid-column:span 6}
}
.explore__item{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--card);
  display:flex;flex-direction:column}
.explore__vis{aspect-ratio:4/3;background:var(--paper-2);border-bottom:1px solid var(--line);display:grid;place-items:center}
.explore__vis .placeholder{font-size:var(--t-xs);font-weight:600;color:var(--muted)}
.explore__txt{padding:var(--s3) var(--s3) var(--s4);flex:1}
.explore__txt h4{font-size:var(--t-body);font-weight:700;letter-spacing:-.012em;margin-bottom:.4rem}
.explore__txt p{font-size:var(--t-xs);color:var(--muted);line-height:1.6}

.callout{margin:clamp(2rem,4vw,var(--s6)) 0;padding:clamp(1.25rem,2.5vw,1.9rem);
  border-left:3px solid var(--navy);background:var(--paper-2);border-radius:0 12px 12px 0}
.callout .label{display:block;margin-bottom:var(--s1)}
.callout p{font-size:var(--t-lead);line-height:1.45;letter-spacing:-.012em;color:var(--ink)}

.metrics{display:grid;gap:clamp(1.5rem,3vw,var(--s5));grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  margin:clamp(2rem,4vw,var(--s6)) 0}
.metrics__item{padding-top:var(--s3);border-top:2px solid var(--navy)}
.metrics__item .val{font-size:clamp(2rem,3.4vw,2.9rem);font-weight:700;letter-spacing:-.04em;line-height:1;
  font-variant-numeric:tabular-nums}
.metrics__item .key{margin-top:.6rem;font-size:var(--t-xs);color:var(--muted);line-height:1.5}

.next-case{display:block;text-decoration:none;padding-block:clamp(2.5rem,5vw,var(--s7));border-top:1px solid var(--line)}
.next-case .label{display:block}
.next-case h3{font-size:var(--t-h2);font-weight:700;letter-spacing:-.034em;margin-top:var(--s2);transition:color .25s var(--ease)}
.next-case:hover h3{color:var(--navy)}

/* --- 12. Contact / footer ------------------------------------------------ */
.contact h2{font-size:var(--t-h1);font-weight:700;letter-spacing:-.036em;line-height:1.04;max-width:16ch}
.contact__links{margin-top:clamp(2rem,4vw,2.75rem);display:flex;flex-wrap:wrap;gap:var(--s2)}
.btn{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;padding:.7rem 1.15rem;
  border-radius:9px;font-size:var(--t-sm);font-weight:600;border:1px solid var(--line-int);
  transition:background .2s,color .2s,border-color .2s}
.btn:hover{border-color:var(--ink)}
.btn--primary{background:var(--navy);color:var(--on-accent);border-color:var(--navy)}
.btn--primary:hover{background:transparent;color:var(--ink)}

.site-foot{border-top:1px solid var(--line);padding-block:var(--s5)}
.site-foot__in{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s5);align-items:center;justify-content:space-between}
.site-foot p{font-size:var(--t-sm);color:var(--muted)}
.site-foot__in .hint{display:inline-flex;align-items:center;gap:.4rem}
@media(max-width:720px){.site-foot__in .hint{display:none}}
.kbd{font-family:ui-monospace,monospace;font-size:.72rem;padding:.1rem .34rem;border:1px solid var(--line-int);
  border-bottom-width:2px;border-radius:5px;color:var(--muted);background:var(--card);cursor:pointer}

/* --- 13. Motion ---------------------------------------------------------- */
/* Two properties, a long decelerating curve, and a short travel. Opacity
   lands before the movement finishes, so a block is readable while it is
   still settling rather than arriving and then being read. */
.js [data-reveal]{ opacity:0; transform:translateY(20px); }
.js [data-reveal].is-in{
  opacity:1; transform:none;
  transition:opacity .7s cubic-bezier(.25,.7,.35,1),
             transform 1s cubic-bezier(.19,.85,.28,1);
}
/* These two use data-reveal only to start an inner animation — they must
   not fade, or the thing inside them fades twice. */
.js .work-card[data-reveal],
.js .ba[data-reveal]{ opacity:1; transform:none; }
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
  [data-reveal]{opacity:1!important;transform:none!important}
  html{scroll-behavior:auto}
}

/* --- 14. Grid overlay (press G) ------------------------------------------ */
.grid-overlay{position:fixed;inset:0;z-index:90;pointer-events:none;opacity:0;transition:opacity .25s ease;display:block}
.grid-overlay[data-on="true"]{opacity:1}
.grid-overlay__cols{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad);
  display:grid;grid-template-columns:repeat(12,1fr);gap:var(--s4);height:100%}
.grid-overlay__cols i{background:var(--navy-soft);border-left:1px solid var(--navy);border-right:1px solid var(--navy);opacity:.5}
.grid-overlay__read{position:fixed;bottom:14px;left:50%;transform:translateX(-50%);
  font-family:ui-monospace,monospace;font-size:.64rem;letter-spacing:.06em;text-transform:uppercase;
  background:var(--ink);color:var(--paper);padding:.35rem .7rem;border-radius:6px;white-space:nowrap}
@media(max-width:720px){.grid-overlay__cols{grid-template-columns:repeat(4,1fr)}}

/* --- 15. Draft warnings — DELETE BEFORE GOING LIVE ----------------------- */
.draft-warn{margin:var(--s4) 0;padding:.9rem 1.1rem;border-radius:9px;border:1px dashed #B4442A;
  background:rgba(180,68,42,.07);font-size:var(--t-xs);line-height:1.6;color:#8F2F17}
.draft-warn b{font-weight:700;letter-spacing:.05em;text-transform:uppercase;display:block;margin-bottom:.3rem;font-size:.7rem}

/* --- 16. Live embed + guided viewing ------------------------------------- */
.embed{margin:clamp(2rem,4vw,var(--s6)) 0;border:1px solid var(--line);border-radius:14px;overflow:hidden;
  background:var(--card);box-shadow:var(--shadow-2)}
.embed__bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s1) var(--s3);padding:.7rem var(--s3);
  border-bottom:1px solid var(--line);background:var(--paper-2)}
.embed__bar .live{margin-left:auto;font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--navy);display:inline-flex;align-items:center;gap:.35rem}
.embed__bar .live::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--navy)}
/* The rig is a phone simulator and its pages are images built at phone width.
   Rendering it wide upscales those assets and softens them — at 430px every
   asset downscales 2.6x or better, so it is shown at the width it was built
   for, in a device frame, on a plate. */
.embed__frame{background:var(--navy-deep);display:grid;place-items:center;
  padding:clamp(1.5rem,4vw,2.75rem) 1rem}
.embed__device{width:430px;max-width:100%;border-radius:30px;background:#000;padding:9px;
  box-shadow:0 2px 6px rgba(0,0,0,.4),0 30px 60px -24px rgba(0,0,0,.55)}
.embed__device iframe{width:100%;height:860px;border:0;border-radius:22px;display:block;background:#14141C}
@media(max-width:520px){
  .embed__device{border-radius:22px;padding:6px}
  .embed__device iframe{height:680px;border-radius:17px}
}
.embed__foot{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s3);align-items:center;padding:.7rem var(--s3);
  border-top:1px solid var(--line);background:var(--paper-2);font-size:var(--t-xs);color:var(--muted)}
.embed__foot a{color:var(--navy);font-weight:600}

/* Four screens, four things to notice. The image carries the claim. */
.notice-list{display:grid;gap:var(--s3);margin:clamp(1.75rem,3vw,2.25rem) 0;
  padding-left:0!important;grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.notice-list li{list-style:none;display:flex;flex-direction:column;background:var(--card);
  border:1px solid var(--line);border-radius:14px;overflow:hidden}
.notice-list .shot{aspect-ratio:3/4;background:var(--paper-2);border-bottom:1px solid var(--line);overflow:hidden}
.notice-list .shot img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block}
.notice-list .txt{padding:var(--s3);flex:1}
.notice-list .n{display:block;font-size:var(--t-xs);font-weight:700;color:var(--navy);
  margin-bottom:.4rem;font-variant-numeric:tabular-nums}
.notice-list h4{font-size:var(--t-body);font-weight:700;letter-spacing:-.012em;margin-bottom:.3rem}
.notice-list p{font-size:var(--t-sm);color:var(--muted);line-height:1.55;max-width:none}

/* --- 17. Kit demo (case 02) ---------------------------------------------- */
.demo{margin:clamp(2rem,4vw,var(--s6)) 0;border:1px solid var(--line);border-radius:14px;overflow:hidden;
  background:var(--card);box-shadow:var(--shadow-2)}
.demo__bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2) var(--s4);padding:.8rem var(--s3);
  border-bottom:1px solid var(--line);background:var(--paper-2)}
.demo__grp{display:flex;align-items:center;gap:var(--s1)}
.demo__live{margin-left:auto;font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--navy);display:inline-flex;align-items:center;gap:.35rem}
.demo__live::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--navy)}
.seg{display:inline-flex;border:1px solid var(--line-int);border-radius:8px;overflow:hidden;background:var(--card)}
.seg button{background:none;border:0;padding:.32rem .68rem;font-size:var(--t-xs);font-weight:600;cursor:pointer;
  color:var(--muted);transition:background .2s,color .2s}
.seg button+button{border-left:1px solid var(--line-int)}
.seg button:hover{color:var(--ink)}
.seg button[aria-pressed="true"]{background:var(--navy);color:var(--on-accent)}
.demo__stage{display:grid}
@media(min-width:780px){.demo__stage{grid-template-columns:minmax(0,1fr) 250px}}
.demo__canvas{padding:clamp(1.25rem,3vw,var(--s5))}
.demo__meta{border-top:1px solid var(--line);padding:var(--s3);background:var(--paper-2)}
@media(min-width:780px){.demo__meta{border-top:0;border-left:1px solid var(--line)}}
.k{--k-gap:1.15rem;max-width:460px}
.k[data-density="compact"]{--k-gap:.7rem}
.k>*+*{margin-top:var(--k-gap)}
.k-field label{display:block;font-size:var(--t-xs);font-weight:600;margin-bottom:.3rem}
.k-field input,.k-field select{width:100%;padding:.58rem .7rem;border:1px solid var(--line-int);border-radius:8px;
  background:var(--paper);font-size:var(--t-sm);transition:border-color .2s,box-shadow .2s}
.k[data-density="compact"] .k-field input,.k[data-density="compact"] .k-field select{padding:.38rem .6rem}
.k-field input:focus,.k-field select:focus{outline:0;border-color:var(--navy);box-shadow:0 0 0 3px var(--navy-soft)}
.k-field .hint{display:block;margin-top:.3rem;font-size:var(--t-xs);color:var(--muted);line-height:1.45}
.k-field[data-state="error"] input{border-color:#B4442A;box-shadow:0 0 0 3px rgba(180,68,42,.12)}
.k-field[data-state="error"] .hint{color:#8F2F17}
.k-alert{display:flex;gap:.6rem;padding:.7rem .8rem;border-radius:9px;background:var(--navy-soft);
  border:1px solid var(--line);font-size:var(--t-xs);line-height:1.5;color:var(--ink)}
.k-alert svg{width:16px;height:16px;flex:none;margin-top:.12rem;color:var(--navy)}
.k-actions{display:flex;gap:.55rem;flex-wrap:wrap}
.k-btn{padding:.55rem 1rem;border-radius:8px;font-size:var(--t-xs);font-weight:600;border:1px solid var(--line-int);
  background:var(--paper);cursor:pointer;white-space:nowrap;transition:background .2s,border-color .2s,opacity .2s}
.k-btn--primary{background:var(--navy);color:var(--on-accent);border-color:var(--navy)}
.k-btn--primary:hover{background:transparent;color:var(--ink)}
.k-btn:hover{border-color:var(--ink)}
.k-btn[disabled]{opacity:.45;cursor:not-allowed}
.k-actions.is-overflowing{position:relative}
.k-actions.is-overflowing::after{content:attr(data-warn);position:absolute;inset:-6px;border:1px dashed #B4442A;
  border-radius:9px;pointer-events:none;font-size:.6rem;color:#8F2F17;display:flex;align-items:flex-start;
  justify-content:flex-end;padding:2px 4px}
.readout{display:grid;gap:var(--s2)}
.readout__row{display:grid;gap:.25rem}
.readout__row .v{font-size:1.45rem;font-weight:700;letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}
.readout__row .k2{font-size:var(--t-xs);color:var(--muted);line-height:1.4}
.bar{height:4px;border-radius:2px;background:var(--paper-2);overflow:hidden;margin-top:.3rem}
.bar i{display:block;height:100%;background:var(--navy);transition:width .45s var(--ease)}
.demo__note{padding:.75rem var(--s3);border-top:1px solid var(--line);font-size:var(--t-xs);color:var(--muted);
  background:var(--paper-2);line-height:1.55}

/* --- 18. Small screens --------------------------------------------------- */
@media(max-width:560px){
  .ident__name span,.ident__back span{display:none}
}
/* overflow-x:hidden here makes the root a scroll container and silently kills
   position:sticky (the case-study TOC). `clip` prevents the sideways scroll
   without creating a scroll container. */
body{overflow-x:clip}

@media print{.next-case,.draft-warn{display:none}body{background:#fff;color:#000}}

/* --- 19. Reading measure at 1600 ----------------------------------------
   The column is wide so media can use it. Text must not follow it out —
   at full width the prose ran to ~143 characters per line. Only direct
   children of a case section are capped, so components stay full-bleed. */
.case-section > p,
.case-section > ul,
.case-section > ol,
.case-section > h3 { max-width: 68ch; }
.callout p { max-width: 62ch; }
.notice-list p { max-width: 66ch; }

/* Preview panes get shallower as the card gets wider, or they dominate */
@media (min-width: 1200px) { .work-card__vis { aspect-ratio: 3 / 2; } }

/* --- 20. Imagery --------------------------------------------------------- */
/* The kit screenshot is 1.62:1 against a 3:2 pane, so cover trims the sides.
   Anchor left so the trim comes off the right, where the crop cuts through UI.
   Scoped to that image — the Harper composite crops vertically and wants centre. */
.work-card__vis img[src*="ui-kit.png"] { object-position: left center; }
figure img { display: block; background: var(--paper-2); }

/* --- 21. Card meta — channels and collaborators --------------------------
   A reusable pair of labelled chip rows. Group one takes icons (channels,
   surfaces, platforms); group two is text only, so it scales to any set of
   teams without needing an icon drawn for each. */
.card-meta{margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line);
  display:grid;gap:var(--s2)}
.card-meta__grp{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem .5rem}
.card-meta__k{font-size:var(--t-label);font-weight:600;color:var(--muted);
  flex:0 0 88px;min-width:88px}
.chips{display:flex;flex-wrap:wrap;gap:.35rem;list-style:none;padding:0;margin:0}
.chip{display:inline-flex;align-items:center;gap:.32rem;padding:.22rem .55rem;
  border:1px solid var(--line);border-radius:999px;font-size:var(--t-xs);
  color:var(--muted);white-space:nowrap;line-height:1.4}
.chip svg{width:13px;height:13px;flex:none;color:var(--navy)}
@media(max-width:560px){
  .card-meta__k{flex-basis:100%;min-width:0}
}

/* --- 22. Case bento — the at-a-glance block at the top of a case study ----
   Reusable. Blocks declare a width class; the feature block takes the tint. */
.case-bento{margin-top:clamp(2rem,4vw,var(--s6));display:grid;gap:var(--s2);grid-template-columns:1fr}
@media(min-width:700px){
  .case-bento{grid-template-columns:repeat(6,1fr)}
  .bento--w2{grid-column:span 2}
  .bento--w3{grid-column:span 3}
  .bento--w4{grid-column:span 4}
}
.bento{background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:clamp(1.15rem,2.2vw,1.5rem) clamp(1.15rem,2vw,1.6rem);
  display:flex;flex-direction:column;gap:.55rem}
.bento--feature{background:var(--navy-deep);border-color:transparent;color:var(--plate-ink)}
.bento--feature .bento__k{color:var(--plate-acc)}
.bento--feature .bento__lead{color:var(--plate-ink)}
.bento--feature .bento__sub{color:var(--plate-muted)}
.bento__k{font-size:.95rem;font-weight:600;color:var(--navy);letter-spacing:-.008em}
.bento__lead{font-size:clamp(1.02rem,1.5vw,1.18rem);line-height:1.5;letter-spacing:-.014em;
  color:var(--ink);font-weight:500;max-width:34ch}
.bento__big{font-size:clamp(1.7rem,2.8vw,2.2rem);font-weight:700;letter-spacing:-.036em;
  line-height:1;font-variant-numeric:tabular-nums}
.bento__v{font-size:1.02rem;font-weight:700;letter-spacing:-.018em;line-height:1.3}
.bento__sub{font-size:var(--t-xs);color:var(--muted);line-height:1.5}
.bento ul{list-style:none;padding:0;margin:0;display:grid;gap:.5rem}
.bento li{font-size:var(--t-sm);color:var(--muted);line-height:1.5;padding-left:.95rem;position:relative}
.bento li::before{content:"";position:absolute;left:0;top:.62em;width:6px;height:1px;background:var(--navy)}
.bento .chips{margin-top:.1rem}

/* --- 23. Chips inside a bento block --------------------------------------
   Fixes two collisions: `.bento ul` (grid) was beating `.chips` (flex) on
   specificity so chips stacked full-width, and `.bento li::before` was
   drawing its dash marker on them. Inside a bento they are plain rows —
   no pill, no border. */
.bento ul.chips{display:flex;flex-wrap:wrap;gap:.55rem 1.25rem}
.bento .chips li{padding-left:0}
.bento .chips li::before{content:none}
.bento .chip{border:0;border-radius:0;padding:0;color:var(--ink);
  font-size:var(--t-sm);gap:.5rem;line-height:1.5}
.bento .chip svg{width:15px;height:15px}

/* Tool logos — normalised to one box so different marks sit at one weight */
.logo{width:18px;height:18px;flex:none;display:block;object-fit:contain}

/* --- 25. Partnership lockup ----------------------------------------------
   Sized by height, not width, so any lockup sits at the same optical weight
   whatever its aspect ratio. Deliberately small — a credit, not a banner. */
.case-lockup{margin-bottom:var(--s3);display:block}
.case-lockup img{height:36px;width:auto;max-width:70%;opacity:.92;display:block}
@media(max-width:560px){.case-lockup img{height:28px;max-width:85%}}

/* --- 26. Links -----------------------------------------------------------
   Two-phase underline. With no accent hue the affordance has to be motion
   and weight, not colour: the resting hairline retracts to the right, then
   a solid rule draws back in from the left. */
.work-card__more,
.next-case .label + h3,
.prose a,
.also a,
.embed__foot a,
.ident__back{ position:relative; }

.work-card__more{ padding-bottom:2px; }
.work-card__more::before,
.work-card__more::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:currentColor;
}
.work-card__more::after{
  opacity:.3;transform-origin:right;transform:scaleX(1);
  transition:transform .42s cubic-bezier(.4,0,.2,1);
}
.work-card__more::before{
  transform-origin:left;transform:scaleX(0);
  transition:transform .55s cubic-bezier(.2,.7,.3,1) .3s;
}
.work-card:hover .work-card__more::after{ transform:scaleX(0); }
.work-card:hover .work-card__more::before{ transform:scaleX(1); }
.work-card__more svg{ transition:transform .5s cubic-bezier(.2,.7,.3,1); }
.work-card:hover .work-card__more svg{ transform:translateX(5px); }

/* Prose and inline links get the same two-phase rule */
.prose a, .also a, .embed__foot a{
  text-decoration:none;color:var(--ink);font-weight:600;
  background-image:none;box-shadow:none;padding-bottom:1px;
}
.prose a::before,.prose a::after,
.also a::before,.also a::after,
.embed__foot a::before,.embed__foot a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:currentColor;
}
.prose a::after,.also a::after,.embed__foot a::after{
  opacity:.3;transform-origin:right;transform:scaleX(1);
  transition:transform .42s cubic-bezier(.4,0,.2,1);
}
.prose a::before,.also a::before,.embed__foot a::before{
  transform-origin:left;transform:scaleX(0);
  transition:transform .55s cubic-bezier(.2,.7,.3,1) .3s;
}
.prose a:hover::after,.also a:hover::after,.embed__foot a:hover::after{ transform:scaleX(0); }
.prose a:hover::before,.also a:hover::before,.embed__foot a:hover::before{ transform:scaleX(1); }
.prose a:hover,.also a:hover{ color:var(--ink); }

/* Buttons hold their shape and drop their fill */
.btn{ transition:background .3s cubic-bezier(.2,.7,.3,1),color .3s cubic-bezier(.2,.7,.3,1),border-color .3s cubic-bezier(.2,.7,.3,1); }

/* Card: a quiet lift, border doing the work rather than a heavy shadow */
.work-card .work-card__vis img{ transition:transform .6s cubic-bezier(.2,.7,.3,1); }
.work-card:hover .work-card__vis img{ transform:scale(1.025); }

/* Inside a plate the drawing rule is the one hit of metal on the site */
.band a::before, .bento--feature a::before{ background:var(--plate-acc); }

/* --- 27. Emphasis without colour ----------------------------------------
   The accent is the ink, so an accent-coloured <em> would be invisible.
   True italic (not synthesised) carries the emphasis instead. */
.hero h1 em, .prose em, .callout em, .band em{ font-style:italic; color:inherit; }
.hero h1 em{ font-style:italic; }

/* --- 28. Alternating cards ----------------------------------------------
   Two identical white cards is what made the page feel flat. One card sits
   on the plate instead, so the work section has a rhythm rather than a list. */
.work-card--plate{ background:var(--navy-deep); border-color:transparent; color:var(--plate-ink); }
.work-card--plate .work-card__num{ color:var(--plate-acc); }
.work-card--plate h3{ color:var(--plate-ink); }
.work-card--plate:hover h3{ color:var(--plate-acc); }
.work-card--plate .work-card__stats{ border-top-color:rgba(243,241,236,.16); }
.work-card--plate .stat__key,
.work-card--plate .card-meta__k,
.work-card--plate .chip{ color:var(--plate-muted); }
.work-card--plate .chip{ border-color:rgba(243,241,236,.18); }
.work-card--plate .chip svg{ color:var(--plate-acc); }
.work-card--plate .card-meta{ border-top-color:rgba(243,241,236,.16); }
.work-card--plate .work-card__more{ color:var(--plate-acc); }
.work-card--plate .work-card__vis{ background:rgba(243,241,236,.06); border-color:rgba(243,241,236,.16); }
.work-card--plate:hover{ border-color:var(--plate-acc); }

/* Accent shows up where it should: labels, section rules, list markers */
.section__head::after{ background:var(--navy); }
.metrics__item{ border-top-color:var(--navy); }
.callout{ border-left-color:var(--navy); }
.bento__k{ color:var(--navy); }
.hero__meta dt{ color:var(--navy); }
.case-topline dt{ color:var(--navy); }
.work-card__num{ color:var(--navy); }
.work-card__more{ color:var(--navy); }
.also a{ color:var(--navy); }

/* Size is a visual signal only — screen readers still need the verdict */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.explore__vis{position:relative}
.explore__vis img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}

/* --- 29. Work card proportions -------------------------------------------
   The image was centred in a much taller column, leaving dead space top and
   bottom. Stretching it to the card height removes that, and a smaller title
   plus a two-up stat row takes ~150px off the depth. */
@media (min-width: 960px){
  .work-card{ align-items:stretch; }
  .work-card > div:first-child{ display:flex; flex-direction:column; }
  .work-card__vis{ aspect-ratio:auto; height:100%; min-height:340px; }
}
/* Title: a size down, and wider measure so it sets in fewer lines */
.work-card h3{
  font-size:clamp(1.5rem,2.6vw,2.05rem);
  max-width:24ch;
  margin-top:.7rem;
}
/* Stats sit two-up rather than stacking */
.work-card__stats{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--s3); margin-top:var(--s3); padding-top:var(--s3);
}
.stat__val{ font-size:clamp(1.15rem,1.7vw,1.4rem); }
.stat__key{ margin-top:.35rem; max-width:24ch; }
/* Meta rows: tighter, and the CTA pinned to the bottom of the column */
.card-meta{ margin-top:var(--s3); padding-top:var(--s3); gap:.55rem; }
.card-meta__k{ flex-basis:78px; min-width:78px; }
.work-card__more{ margin-top:auto; padding-top:var(--s4); }

/* --- 30. Card breathing --------------------------------------------------
   Shallower is right, but the previous pass compressed the blocks against
   each other. The image stretches with the column, so extra air costs less
   depth than it looks — the card can breathe and still be half its old size. */
.work-card{
  padding:clamp(2rem,3.4vw,3rem);
  gap:clamp(2rem,4.5vw,3.75rem);
}
.work-card h3{ margin-top:var(--s3); line-height:1.06; }
.work-card__stats{
  margin-top:var(--s5);
  padding-top:var(--s5);
  gap:var(--s4);
}
.card-meta{
  margin-top:var(--s5);
  padding-top:var(--s5);
  gap:var(--s3);
}
.card-meta__grp{ gap:.5rem .6rem; }
.chips{ gap:.45rem; }
.chip{ padding:.3rem .65rem; }
.work-card__more{ padding-top:var(--s5); }

/* --- 31. Card meta alignment ---------------------------------------------
   Was flex-wrap, so a row with more chips than fit dropped the whole set
   below its label while shorter rows sat alongside. A two-column grid keeps
   the label fixed and lets the chips wrap inside their own column, so every
   row starts at the same x whatever it contains. */
.card-meta__grp{
  display:grid;
  grid-template-columns:88px minmax(0,1fr);
  gap:.6rem;
  align-items:start;
}
.card-meta__k{
  flex:none; min-width:0; flex-basis:auto;
  padding-top:.34rem;   /* optically centres the label on the first chip row */
}
@media(max-width:560px){
  .card-meta__grp{ grid-template-columns:1fr; gap:.45rem; }
  .card-meta__k{ padding-top:0; }
}

/* --- 32. Pinned preview panes --------------------------------------------
   Stretching the pane to the text column made the two cards' images different
   heights, and turned a 4:3 export into a heavy side crop. Pinning to 4:5
   gives one predictable export size and two cards that match. The pane is
   top-aligned so it reads as a deliberate object rather than a stretched fill. */
@media (min-width: 960px){
  .work-card{ align-items:start; }
  .work-card__vis{ aspect-ratio:4 / 5; height:auto; min-height:0; }
}

/* --- 33. Composed thumbnails ---------------------------------------------
   Screens sit on a gradient built from the palette rather than baked into a
   flat export: the ground always matches the theme, files stay small, and a
   screen can be swapped without recomposing anything.
   Selectors use nth-of-type — .shots__bg is the first child, so nth-child
   would be off by one. */
.work-card__vis--shots{ overflow:hidden; }
.shots{ position:absolute; inset:0; }
.shots__bg{ position:absolute; inset:0; }
.shots img{
  position:absolute; top:50%; left:50%; width:48%; height:auto;
  border-radius:16px; display:block;
  box-shadow:0 2px 8px rgba(0,0,0,.3), 0 30px 50px -20px rgba(0,0,0,.55);
}
/* A diagonal cascade, back to front. Three is the most this pane takes —
   a symmetrical fan of three gets cramped at 481px, a stagger reads as depth. */
.shots img:nth-of-type(1){ transform:translate(-78%,-62%) rotate(-7deg); z-index:1; }
.shots img:nth-of-type(2){ transform:translate(-50%,-50%) rotate(-1deg); z-index:2; }
.shots img:nth-of-type(3){ transform:translate(-22%,-38%) rotate(5deg);  z-index:3; }

.shots__bg--warm{
  background:
    radial-gradient(120% 90% at 25% 8%,  #5A5047 0%, transparent 60%),
    radial-gradient(110% 80% at 85% 95%, #2B2521 0%, transparent 62%),
    linear-gradient(158deg, #453C34 0%, #241F1B 100%);
}
.shots__bg--bone{
  background:
    radial-gradient(120% 90% at 20% 5%, #FBF9F4 0%, transparent 62%),
    linear-gradient(158deg, #EFEBE2 0%, #D8D0C2 100%);
}

/* --- 34. The screens settle onto the ground -------------------------------
   Gradient paints immediately; the back plate arrives, then the front one a
   beat later so it reads as being placed on top rather than both sliding in. */
.js [data-reveal] .shots img{
  opacity:0;
  transition:transform 1.15s cubic-bezier(.16,.84,.28,1), opacity 1.3s cubic-bezier(.25,.6,.35,1);
}
.js [data-reveal] .shots img:nth-of-type(1){ transform:translate(-78%,-50%) rotate(-12deg) scale(.94); }
.js [data-reveal] .shots img:nth-of-type(2){ transform:translate(-50%,-38%) rotate(-5deg)  scale(.94); }
.js [data-reveal] .shots img:nth-of-type(3){ transform:translate(-22%,-26%) rotate(10deg)  scale(.94); }
.js [data-reveal].is-in .shots img{ opacity:1; }
.js [data-reveal].is-in .shots img:nth-of-type(1){ transform:translate(-78%,-62%) rotate(-7deg); transition-delay:.1s; }
.js [data-reveal].is-in .shots img:nth-of-type(2){ transform:translate(-50%,-50%) rotate(-1deg); transition-delay:.34s; }
.js [data-reveal].is-in .shots img:nth-of-type(3){ transform:translate(-22%,-38%) rotate(5deg);  transition-delay:.58s; }

/* A small drift apart on hover */
.work-card:hover .shots img:nth-of-type(1){ transform:translate(-83%,-63%) rotate(-8.5deg); }
.work-card:hover .shots img:nth-of-type(2){ transform:translate(-50%,-51%) rotate(-1deg); }
.work-card:hover .shots img:nth-of-type(3){ transform:translate(-17%,-37%) rotate(6.5deg); }

@media(max-width:640px){ .shots img{ width:54%; } }
@media (prefers-reduced-motion: reduce){
  .js [data-reveal] .shots img,
  .js [data-reveal].is-in .shots img{ opacity:1 !important; transition:none !important; }
  .js [data-reveal] .shots img:nth-of-type(1),
  .js [data-reveal].is-in .shots img:nth-of-type(1){ transform:translate(-78%,-62%) rotate(-7deg) !important; }
  .js [data-reveal] .shots img:nth-of-type(2),
  .js [data-reveal].is-in .shots img:nth-of-type(2){ transform:translate(-50%,-50%) rotate(-1deg) !important; }
  .js [data-reveal] .shots img:nth-of-type(3),
  .js [data-reveal].is-in .shots img:nth-of-type(3){ transform:translate(-22%,-38%) rotate(5deg) !important; }
}

/* --- 35. Single wide artefact --------------------------------------------
   A landscape screen in a portrait pane. Rather than shrink it to fit and
   leave the ground empty, it sits oversized and bleeds off the right edge —
   reading as a detail of something larger, with the sidebar and title, the
   parts that carry at this size, kept in frame. */
.shots--single img{
  width:152%; max-width:none;   /* the reset clamps to 100% and kills the bleed */
  border-radius:12px;
  box-shadow:0 2px 8px rgba(22,19,15,.10), 0 30px 50px -22px rgba(22,19,15,.30);
}
.shots--single img:nth-of-type(1){ transform:translate(-46%,-50%) rotate(-2.5deg); z-index:1; }
.js [data-reveal] .shots--single img:nth-of-type(1){ transform:translate(-46%,-42%) rotate(-5deg) scale(.96); }
.js [data-reveal].is-in .shots--single img:nth-of-type(1){ transform:translate(-46%,-50%) rotate(-2.5deg); transition-delay:.12s; }
.work-card:hover .shots--single img:nth-of-type(1){ transform:translate(-44%,-51%) rotate(-1.6deg); }
@media (prefers-reduced-motion: reduce){
  .js [data-reveal] .shots--single img:nth-of-type(1),
  .js [data-reveal].is-in .shots--single img:nth-of-type(1){ transform:translate(-46%,-50%) rotate(-2.5deg) !important; }
}
@media(max-width:640px){ .shots--single img{ width:132%; max-width:none; } }

/* --- 36. Slow pan on the wide artefact ------------------------------------
   The pan lives on a wrapper, not the image: the image already carries the
   entrance transform and its angle, and an animation on the same element
   would override those. Wrapper pans, image holds its position.
   Travel is ±4% of the pane — the image overhangs by more than that on both
   sides, so no edge is ever exposed. */
.shots__pan{ position:absolute; inset:0; will-change:transform; }
.shots--single .shots__pan{ animation:kit-pan 22s cubic-bezier(.45,0,.55,1) infinite alternate; }
@keyframes kit-pan{
  from{ transform:translateX(-10%); }
  to  { transform:translateX(10%);  }
}
@media (prefers-reduced-motion: reduce){
  .shots--single .shots__pan{ animation:none; }
}

/* --- 37. The two wins -----------------------------------------------------
   The close of the delivery section: what the customer got, and what the team
   kept. Two panels rather than prose, because the pairing is the point — one
   is the outcome of the study, the other the reason the work outlived it. */
.wins{
  display:grid; gap:var(--s2);
  grid-template-columns:1fr;
  margin:clamp(2rem,4vw,var(--s6)) 0;
}
@media(min-width:720px){ .wins{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.win{
  padding:clamp(1.25rem,2.4vw,1.75rem);
  background:var(--paper-2); border-radius:14px;
  border-top:2px solid var(--navy);
}
.win .label{ display:block; color:var(--navy); margin-bottom:var(--s2); }
.win p{ color:var(--ink); font-size:1.02rem; line-height:1.5; letter-spacing:-.01em; }
.win p+p{ margin-top:.55rem; font-size:var(--t-sm); color:var(--muted); line-height:1.55; }

/* --- 38. Identity row ------------------------------------------------------
   Name (or the way back) on the left, monogram on the right. The mark is
   inlined rather than an <img> so it inherits colour and can pick up the
   bronze on hover, like every other link on the site. */
.ident{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--s4);
}
.ident__logo{
  display:inline-flex; flex:none; color:var(--ink);
  transition:color .25s var(--ease), transform .25s var(--ease);
}
.ident__logo svg{ height:24px; width:auto; display:block; }
.ident__logo:hover{ color:var(--navy); transform:translateY(-1px); }
@media(max-width:560px){ .ident__logo svg{ height:20px; } }

/* ==========================================================================
   39. Dark inversion — the surfaces that need more than a token swap
   ========================================================================== */

/* Both work cards are now the same lifted surface. The old --plate variant
   existed to make one card dark on a light page; with the whole site dark it
   would only make card 01 sink back into the ground. */
.work-card--plate{ background:var(--card); border-color:var(--line); color:var(--ink); }
.work-card--plate h3{ color:var(--ink); }

/* The lift: a warm sheen off the top edge, a hairline of light on the rim,
   and a deep soft shadow. This is what separates a card from the page. */
.work-card,
.hero__meta>div{
  background-image:linear-gradient(180deg, rgba(243,241,236,.035) 0%, rgba(243,241,236,0) 42%);
  box-shadow:var(--lift-edge), 0 18px 40px -24px rgba(0,0,0,.8);
}
.work-card:hover,
.hero__meta>div:hover{
  box-shadow:var(--lift-edge), 0 30px 60px -26px rgba(0,0,0,.9);
}
.work-card:hover{ border-color:var(--line-int); }
.work-card--plate:hover{ border-color:var(--line-int); }
.work-card--plate:hover h3{ color:var(--navy); }

/* The feature tile keeps its distinction by sitting a step higher again */
.hero__meta>div:nth-child(2){ background-color:var(--navy-soft); border-color:transparent; }

/* Recessed panels sink rather than lift, so the hierarchy stays legible */
.callout,
.win,
.section--tint{ background-color:var(--paper-2); }
.win{ box-shadow:var(--lift-edge); }

/* The preview pane inside a card is a window, not another card */
.work-card--plate .work-card__vis,
.work-card__vis{ background:var(--navy-deep); border-color:var(--line); }

/* Card 02's ground was a light gradient — it has to invert with everything else */
.shots__bg--bone{
  background:
    radial-gradient(120% 90% at 20% 5%,  #2A2420 0%, transparent 62%),
    linear-gradient(158deg, #221D19 0%, #100D0B 100%);
}
/* The wide artefact is a light screenshot: soften its shadow so it does not
   glow against the dark, and give it a rim so the edge is not a hard cut */
.shots--single img{
  box-shadow:0 2px 10px rgba(0,0,0,.5), 0 30px 55px -20px rgba(0,0,0,.75);
  outline:1px solid rgba(243,241,236,.08); outline-offset:-1px;
}

/* Draft notes: the light-mode red is unreadable on this ground */
.draft-warn{ border-color:#C2604A; background:rgba(194,96,74,.10); color:#E8A794; }
.k-field[data-state="error"] input{ border-color:#C2604A; box-shadow:0 0 0 3px rgba(194,96,74,.18); }
.k-field[data-state="error"] .hint,
.k-actions.is-overflowing::after{ color:#E8A794; }
.k-actions.is-overflowing::after{ border-color:#C2604A; }

/* The Boden × Harper lockup is dark artwork on a dark ground */
.case-lockup img{ filter:invert(1) brightness(1.08); }

/* The bento tiles are cards too — they lift, and the feature tile is marked
   by sitting a step higher than its neighbours rather than a step darker. */
.bento{
  background-image:linear-gradient(180deg, rgba(243,241,236,.035) 0%, rgba(243,241,236,0) 42%);
  box-shadow:var(--lift-edge), 0 14px 30px -22px rgba(0,0,0,.8);
}
.bento--feature{
  background-color:var(--navy-soft); border-color:rgba(243,241,236,.10);
  box-shadow:var(--lift-edge), 0 20px 40px -22px rgba(0,0,0,.9);
}
.bento--feature .bento__k{ color:var(--navy); }
.bento--feature .bento__lead{ color:var(--ink); }
.bento--feature .bento__sub{ color:var(--muted); }

/* Bento emphasis. The tiles are the scan layer, so the load-bearing phrase in
   each line lifts to full-strength bone while the rest stays muted — the eye
   can read only the bold and still get the argument. */
.bento strong{ color:var(--ink); font-weight:600; }
.bento--feature .bento__lead strong{ color:var(--ink); font-weight:700; }

/* --- 40. Section markers --------------------------------------------------
   The eyebrow was a line of muted text with nothing to anchor it, so sections
   ran together. It now sits under a hairline that spans the column, with a
   champagne segment overlapping the rule at the left — the same device the
   homepage section heads already use, so it reads as one vocabulary. */
.case-section>.label{
  position:relative;
  display:block;
  padding-top:1.15rem;
  border-top:1px solid var(--line);
  margin-bottom:var(--s4);
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.11em;
  text-transform:uppercase;
  color:var(--muted);
}
.case-section>.label::before{
  content:"";
  position:absolute; top:-1px; left:0;
  width:46px; height:2px;
  background:var(--navy);
}
/* More air above each marker, so the rule reads as a boundary not a divider */
.case-section+.case-section{ margin-top:calc(var(--sec-md) + var(--s3)); }
.case-section>h2{ margin-bottom:var(--s4); }

/* With no standfirst the hero is a single column, so the headline needs its
   own measure — otherwise it runs the full width of the page and the line
   breaks fall apart at display size. */
@media(min-width:960px){
  .hero__grid:not(:has(.hero__sub)){ grid-template-columns:minmax(0,1fr); }
  .hero__grid:not(:has(.hero__sub)) h1{ max-width:15ch; }
}

/* --- 41. Before/after and annotated craft figures --------------------------
   Two panels showing the problem, then the reworked version marked up with
   numbered pins and a key. Pins live in the SVG so they stay locked to the
   artwork at any size; the prose sits in HTML so it stays readable. */
.ba{ display:grid; gap:var(--s3); margin:clamp(2rem,4vw,var(--s6)) 0; }
@media(min-width:640px){ .ba{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s4); } }
.ba__item{ display:flex; flex-direction:column; gap:.65rem; }
.ba__cap{ font-size:var(--t-label); font-weight:600; letter-spacing:.06em;
  text-transform:uppercase; color:var(--muted); }
.ba__item--problem .ba__cap{ color:var(--navy); }
.ba figure, .ba img{ margin:0; }
/* Only the plain panel gets card treatment. The peel layers must stay flat —
   a radius or border on those shows up as a rounded edge mid-panel the moment
   a layer moves, and a shadow doubles up three times over. */
.ba__item > img{ border-radius:10px; border:1px solid var(--line); width:100%;
  box-shadow:0 2px 8px rgba(0,0,0,.4), 0 22px 40px -22px rgba(0,0,0,.7); }
.peel__l img{ border-radius:0; border:0; box-shadow:none; }






/* --- 42. The three panels -------------------------------------------------
   Each panel is held in its real on-device state: header dropped below the
   status bar, footer lifted above the address bar. The chrome is static and
   always in view — it is a constant, shown so it is plainly accounted for
   rather than animated as though it were the change.

   The footer is split in three so the Try Before You Buy block can genuinely
   push. The block is always in place, covered by the furniture above it; that
   furniture rises by exactly the block's height and uncovers it, while the
   payment marks below stay anchored. The scroll area gives way by the same
   amount, because it is the only thing in the panel that can. */
.peel{
  position:relative; width:100%; aspect-ratio:750/1624;
  overflow:hidden; background:#0A0908; border:1px solid var(--line);
  box-shadow:0 2px 8px rgba(0,0,0,.4), 0 22px 40px -22px rgba(0,0,0,.7);
}
.peel__l{ position:absolute; inset:0; }
/* The block sits in place from the start, hidden beneath the furniture above
   it. That furniture slides up and uncovers it — an insertion, not a fade. */
.peel__l--foot-b{ z-index:1; }
.peel__l--foot-a{ z-index:2; }
.peel__l--foot-c{ z-index:3; }
.peel__l img{ display:block; width:100%; height:100%; object-fit:cover;
  border-radius:0; border:0; box-shadow:none; }

/* 115.7px of status bar off the top, 181px of Safari off the bottom */
.peel__l--head,
.peel__l--list{ transform:translateY(7.123%); }
.peel__l--foot,
.peel__l--foot-a,
.peel__l--foot-b,
.peel__l--foot-c{ transform:translateY(-11.143%); }

.peel--was  .peel__l--head{ clip-path:inset(0 0 91.195% 0); }
.peel--was  .peel__l--list{ clip-path:inset(8.559% 0 52.568% 0); }
.peel--was  .peel__l--foot{ clip-path:inset(65.702% 0 0 0); }

.peel--tbyb .peel__l--head  { clip-path:inset(0 0 91.195% 0); }
.peel--tbyb .peel__l--list  { clip-path:inset(8.559% 0 62.050% 0); }
.peel--tbyb .peel__l--foot-a{ clip-path:inset(56.219% 0 17.180% 0); }
.peel--tbyb .peel__l--foot-b{ clip-path:inset(82.574% 0 7.451% 0); }
.peel--tbyb .peel__l--foot-c{ clip-path:inset(92.303% 0 0 0); }

.peel--fix  .peel__l--head  { clip-path:inset(0 0 92.241% 0); }
.peel--fix  .peel__l--list  { clip-path:inset(7.512% 0 51.644% 0); }
.peel--fix  .peel__l--foot-a{ clip-path:inset(66.626% 0 15.764% 0); }
.peel--fix  .peel__l--foot-b{ clip-path:inset(83.990% 0 6.158% 0); }
.peel--fix  .peel__l--foot-c{ clip-path:inset(93.596% 0 0 0); }

.squeeze__marks{ position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
/* A dimension arrow rather than a tint: two heads that close on each other
   as the space between them is taken. The stem scales; the heads do not, so
   they keep their shape at any panel width. */
.dim-stem{ stroke:var(--navy); stroke-width:8; fill:none; opacity:.8; }
.dim-head{ fill:var(--navy); opacity:.8; }

/* Panel one is the baseline and never moves. */
.js [data-reveal].is-in .peel--tbyb .peel__l--foot-a{ animation:lift-b 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--tbyb .peel__l--list  { animation:give-list-b 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--tbyb .dim-stem{ transform-origin:48px 290.7px; animation:give-b 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--tbyb .dim-head--b{ animation:close-b 7s var(--ease) infinite; }

.js [data-reveal].is-in .peel--fix .peel__l--foot-a{ animation:lift-c 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--fix .peel__l--list  { animation:give-list-c 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--fix .dim-stem{ transform-origin:40px 273.7px; animation:give-c 7s var(--ease) infinite; }
.js [data-reveal].is-in .peel--fix .dim-head--b{ animation:close-c 7s var(--ease) infinite; }

@keyframes lift-b{ 0%,14%{ transform:translateY(-1.660%); } 44%,82%{ transform:translateY(-11.143%); } 100%{ transform:translateY(-1.660%); } }
@keyframes lift-c{ 0%,14%{ transform:translateY(-1.783%); } 44%,82%{ transform:translateY(-11.143%); } 100%{ transform:translateY(-1.783%); } }
@keyframes give-list-b{
  0%,14%  { transform:translateY(7.123%); clip-path:inset(8.559% 0 52.568% 0); }
  44%,82% { transform:translateY(7.123%); clip-path:inset(8.559% 0 62.050% 0); }
  100%    { transform:translateY(7.123%); clip-path:inset(8.559% 0 52.568% 0); }
}
@keyframes give-list-c{
  0%,14%  { transform:translateY(7.123%); clip-path:inset(7.512% 0 42.284% 0); }
  44%,82% { transform:translateY(7.123%); clip-path:inset(7.512% 0 51.644% 0); }
  100%    { transform:translateY(7.123%); clip-path:inset(7.512% 0 42.284% 0); }
}
@keyframes give-b{ 0%,14%{ transform:scaleY(1.37997); } 44%,82%{ transform:scaleY(1); } 100%{ transform:scaleY(1.37997); } }
@keyframes give-c{ 0%,14%{ transform:scaleY(1.25706); } 44%,82%{ transform:scaleY(1); } 100%{ transform:scaleY(1.25706); } }
@keyframes close-b{ 0%,14%{ transform:translateY(154px); } 44%,82%{ transform:translateY(0); } 100%{ transform:translateY(154px); } }
@keyframes close-c{ 0%,14%{ transform:translateY(152px); } 44%,82%{ transform:translateY(0); } 100%{ transform:translateY(152px); } }
@media (prefers-reduced-motion: reduce){
  .js [data-reveal].is-in .peel--tbyb .peel__l--foot-a,
  .js [data-reveal].is-in .peel--fix  .peel__l--foot-a{ animation:none; transform:translateY(-11.143%); }
  .js [data-reveal].is-in .peel--tbyb .peel__l--list{ animation:none; clip-path:inset(8.559% 0 62.050% 0); }
  .js [data-reveal].is-in .peel--fix  .peel__l--list{ animation:none; clip-path:inset(7.512% 0 51.644% 0); }
  .js [data-reveal].is-in .dim-stem{ animation:none; transform:scaleY(1); }
  .js [data-reveal].is-in .dim-head--b{ animation:none; transform:none; }
}

/* --- 43. Three-up ---------------------------------------------------------- */
@media(min-width:700px){
  .ba{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--s2); }
}
.ba__item--fix .ba__cap{ color:var(--navy); }

/* Changes list, now standing on its own under the row */
.changes{ counter-reset:ch; display:grid; gap:.8rem; margin:var(--s5) 0 0; padding:0; list-style:none; }
@media(min-width:820px){ .changes{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s4) var(--s5); align-items:start; } }
/* Badge is absolutely positioned rather than a grid cell: an li here holds
   three children (the counter, the strong, and a bare text node), and grid
   would blockify all three — dropping the text into a 1.5rem column. */
.changes li{
  position:relative; padding-left:2.1rem;
  font-size:var(--t-sm); line-height:1.55; color:var(--muted);
}
.changes li::before{
  counter-increment:ch; content:counter(ch);
  position:absolute; left:0; top:.05em;
  width:1.5rem; height:1.5rem; border-radius:50%;
  background:var(--navy); color:#16130F;
  font-size:.78rem; font-weight:700;
  display:flex; align-items:center; justify-content:center;
}
/* .prose li+li is (0,1,2) and beats .changes li — match it to win on order */
.changes li + li{ margin-top:0; }
.changes strong{ color:var(--ink); font-weight:600; }

/* --- 44. Text beside figure -----------------------------------------------
   Each block runs as its own two columns — the reasoning on one side, the
   artefact on the other. Pairing the two blocks against each other left one
   column half the height of the other; pairing text against its own figure
   balances, and still brings the second block up the page. */
.pair{ display:grid; gap:var(--s4); margin-top:var(--s6); }
@media(min-width:900px){
  .pair{ grid-template-columns:minmax(0,1fr) minmax(0,1.12fr);
         gap:clamp(1.75rem,3.4vw,var(--s6)); align-items:start; }
}
.pair h3{ margin-top:0; }
.pair__txt > :first-child{ margin-top:0; }
.pair__fig{ margin:0; }
.pair p, .pair ul, .pair h3{ max-width:none; }
.pair ul{ margin-top:var(--s3); }
.pair .callout{ margin:var(--s4) 0 0; }
.pair__aside > :first-child{ margin-top:0; }

/* --- 45. The prototype, beside the brief -----------------------------------
   The device renders at 430px internally — narrowing the iframe would trip
   the prototype's own breakpoints, so it is scaled instead. --mini-scale is
   set from the column width by a ResizeObserver, and the wrapper carries the
   scaled height so the column does not collapse around a transformed child. */
.mini{ position:relative; }
.mini__stage{
  height:calc(878px * var(--mini-scale, 1));
  overflow:hidden;
}
.mini .embed__device{
  transform:scale(var(--mini-scale, 1));
  transform-origin:top left;
  margin:0;
}
.mini .embed__device iframe{ height:860px; }

/* Sketched invitation, pointing at the thing it invites you to use */
.tryit{ display:flex; align-items:flex-start; gap:.4rem; margin-bottom:.35rem; }
.tryit__label{
  font-size:var(--t-label); font-weight:600; letter-spacing:.02em;
  color:var(--navy); padding-top:.55rem; white-space:nowrap;
}
.tryit__arrow{ width:74px; height:52px; flex:none; overflow:visible; }
.tryit__arrow path{
  fill:none; stroke:var(--navy); stroke-width:2.2;
  stroke-linecap:round; stroke-linejoin:round; opacity:.85;
}
.mini .embed__foot{ border:0; background:none; padding:.7rem 0 0; }
@media(max-width:899px){
  .tryit{ margin-top:var(--s4); }
}

/* --- 46. Sticky header ------------------------------------------------------
   Frosted rather than solid: at 72% the page reads through it, so the bar
   feels like a layer over the content rather than a lid on it. The saturate
   is what stops blurred dark tones going muddy. The rule underneath only
   appears once there is something scrolled beneath it. */
:root{ --topbar-h:60px; }
.topbar{
  position:sticky; top:0; z-index:60;
  background:rgba(14,12,11,.72);
  -webkit-backdrop-filter:blur(18px) saturate(150%);
  backdrop-filter:blur(18px) saturate(150%);
  border-bottom:1px solid transparent;
  transition:border-color .35s var(--ease), background-color .35s var(--ease);
}
.topbar[data-stuck="true"]{
  border-bottom-color:var(--line);
  background:rgba(14,12,11,.82);
}
/* No blur support: fall back to near-opaque rather than unreadable */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .topbar{ background:rgba(14,12,11,.96); }
}
/* The row is a bar now, not a spacious block at the top of the page */
.ident{ padding-block:clamp(.8rem,1.5vw,1.05rem); }

/* Anchored jumps and the sticky contents list both have to clear the bar */
.case-section{ scroll-margin-top:calc(var(--topbar-h) + 20px); }
@media(min-width:960px){
  .case-toc{ top:calc(var(--topbar-h) + 24px); }
}

/* --- 47. Homepage fold ------------------------------------------------------
   The hero was carrying 136px above it and 192px between the tiles and the
   work — enough that the first case study started below the fold on a laptop.
   The claim and the evidence should be on screen together, so the air comes
   down and a slice of the first card shows. */
.hero{ padding-block:clamp(2rem,4.6vw,3.75rem) var(--s5); }
#work{ padding-top:var(--s5); }

/* With no standfirst the tiles sit almost against the h1, and a display-size
   heading needs more room than a paragraph did. Scoped to the adjacent case
   so a page that keeps its standfirst is untouched. */
.case-head h1 + .case-bento{ margin-top:clamp(2.5rem,5vw,var(--s7)); }

/* A warm aside rather than a standfirst: smaller than the lead, muted, and
   held to a short measure so it reads as a second thought after the headline
   rather than a paragraph competing with it. */
.hero__note{
  margin-top:clamp(1.1rem,2vw,1.6rem);
  max-width:54ch;
  font-size:clamp(1.02rem,1.25vw,1.14rem);
  line-height:1.55;
  letter-spacing:-.008em;
  color:var(--muted);
}

/* The work has to be plainly in view before any scroll, not sitting on the
   fold line — on a 13in laptop the viewport is nearer 760px than 900. The
   air comes out of the gaps rather than the headline. */
.hero{ padding-block:clamp(1.5rem,3.4vw,2.75rem) var(--s4); }
#work{ padding-top:var(--s4); }
.hero__meta{ margin-top:clamp(1.75rem,3.4vw,2.5rem); }
.hero__meta > div{ padding:clamp(1rem,1.9vw,1.2rem) clamp(1.15rem,2vw,1.5rem); }

/* The closing line answers the four changes above it, so it needs air to read
   as a conclusion rather than a fifth item. */
.changes-out{ margin-top:var(--s6); }



/* --- 48. Customer Service reference ----------------------------------------
   Two pages lifted straight from the PDF. They are light documents on a dark
   page, so they get a rim and a deep shadow to sit as objects rather than
   glowing panels. */
.ref{ display:grid; gap:var(--s3); margin:clamp(2rem,4vw,var(--s6)) 0 0; }
@media(min-width:900px){
  .ref{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s4); align-items:start; }
}
.ref img{
  display:block; width:100%; border-radius:6px;
  outline:1px solid rgba(243,241,236,.09); outline-offset:-1px;
  box-shadow:0 2px 10px rgba(0,0,0,.5), 0 26px 48px -22px rgba(0,0,0,.75);
}

/* The device home screen is a tall portrait shot in a landscape slot — show
   the top of it rather than the middle, where the dead apps are. */
.explore__item[data-verdict="shipped"] .explore__vis img{
  width:100%; height:100%; object-fit:cover; object-position:top center;
}
/* Three explorations: two small side by side, the outcome full width beneath */
@media(min-width:760px){
  .explore:has(> :nth-child(3)):not(:has(> :nth-child(4))) .explore__item:not([data-verdict="shipped"]){ grid-column:span 3; }
  .explore:has(> :nth-child(3)) .explore__item[data-verdict="shipped"]{ grid-column:span 6; }
}


/* The next-case rule sat flush against the last line of the article — its
   padding is inside the border, so it only ever pushed its own content down.
   The gap has to come from a margin above it. */
.next-case{ margin-top:var(--sec-md); }


/* --- 49. CV -----------------------------------------------------------------
   Stu's existing CV, kept to its own structure — badge headings, an org chip
   and a date per role, prose rather than bullets — but rebuilt on the site's
   tokens. The print block at the end flips it back to paper: a dark CV is
   unreadable the moment someone hits Cmd-P, and recruiters print. ------------ */
.cv{ padding-block:var(--s6) var(--sec-md); }

/* Header: photo, name, contact. */
.cvh{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--s4) var(--s5);
  justify-content:space-between; }
.cvh__id{ display:flex; align-items:center; gap:var(--s4); }
.cvh__photo{ width:84px; height:84px; border-radius:50%; object-fit:cover;
  border:1px solid var(--line); box-shadow:var(--lift-edge); flex:none; }
.cvh h1{ font-size:clamp(2rem,4vw,2.9rem); font-weight:700; letter-spacing:-.035em;
  line-height:1; }
.cvh__role{ display:block; margin-top:.4rem; color:var(--muted);
  font-size:var(--t-lead); letter-spacing:-.012em; }
.cvh__contact{ font-size:var(--t-sm); color:var(--muted); text-align:right; }
.cvh__contact p + p{ margin-top:.3rem; }
.cvh__contact b{ color:var(--ink); font-weight:600; }
.cvh__contact a{ color:var(--muted); text-decoration:none; }
.cvh__contact a:hover{ color:var(--navy); }

/* The black section badges, inverted into the accent. */
.badge{ display:inline-block; background:var(--navy); color:var(--on-accent);
  font-size:var(--t-label); font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; padding:.34rem .7rem; border-radius:6px; }
.cv-block{ margin-top:var(--sec-sm); }
.cv-block > .badge + *{ margin-top:var(--s4); }
.cv-block p{ color:var(--muted); max-width:78ch; }
.cv-block p + p{ margin-top:var(--s3); }
.cv-block strong{ color:var(--ink); font-weight:600; }

/* One role: org, title(s), dates. */
.cvrole + .cvrole{ margin-top:var(--s5); padding-top:var(--s5);
  border-top:1px solid var(--line); }
.cvrole__head{ display:flex; flex-wrap:wrap; align-items:center; gap:.45rem var(--s3);
  margin-bottom:var(--s3); }
.org{ font-size:var(--t-xs); font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink); border:1px solid var(--line-int); border-radius:6px; padding:.3rem .6rem; }
.tag{ font-size:var(--t-xs); font-weight:600; letter-spacing:-.005em; color:var(--ink);
  background:var(--card); border:1px solid var(--line); border-radius:6px; padding:.3rem .6rem; }
.when{ margin-left:auto; display:inline-flex; align-items:center; gap:.4rem;
  font-size:var(--t-xs); font-weight:600; color:var(--muted); white-space:nowrap; }
.when svg{ width:14px; height:14px; color:var(--navy); flex:none; }

/* Skills and Toolbox, side by side as in the original. */
.cv-cols{ display:grid; gap:var(--sec-sm); margin-top:var(--sec-sm); }
@media(min-width:720px){ .cv-cols{ grid-template-columns:1fr 1.4fr; gap:var(--s7); } }
.cv-cols .cv-block{ margin-top:0; }
.cv-list{ list-style:none; padding:0; margin-top:var(--s4); color:var(--muted); }
.cv-list li + li{ margin-top:.5rem; }
.cv-list--two{ columns:2; column-gap:var(--s5); }
.cv-list--two li{ break-inside:avoid; }

/* --- Print ------------------------------------------------------------------ */
@media print{
  :root{
    --paper:#fff; --paper-2:#fff; --card:#F4F2EE;
    --ink:#14110F; --muted:#3B3630; --navy:#14110F; --on-accent:#fff;
    --line:#D8D3CB; --line-int:#8C857B; --lift-edge:none;
    color-scheme:light;
  }
  @page{ size:A4; margin:12mm 12mm; }
  body{ background:#fff; color:#14110F; font-size:9.05pt; line-height:1.4; }
  .topbar, .site-foot{ display:none !important; }
  .wrap{ max-width:none; padding-inline:0; }
  .cv{ padding-block:0; }
  .cvh h1{ font-size:20pt; }
  .cvh__photo{ width:58px; height:58px; }
  .cvh__role{ font-size:10.5pt; }
  .cv-block{ margin-top:10pt; }
  .cv-block > .badge + *{ margin-top:6pt; }
  .cv-block p + p{ margin-top:4pt; }
  .badge{ padding:.26rem .58rem; }
  .cvrole__head{ margin-bottom:5pt; gap:.3rem .5rem; }
  .org, .tag, .when{ font-size:8.4pt; padding-block:.22rem; }
  .cv-list{ margin-top:6pt; }
  .cv-list li + li{ margin-top:3pt; }
  .cv-block p{ max-width:none; }
  .cvrole, .cv-cols{ break-inside:avoid; page-break-inside:avoid; }
  .cvrole + .cvrole{ margin-top:7pt; padding-top:7pt; }
  .cv-cols{ margin-top:9pt; gap:var(--s6); }
  .badge{ background:#14110F; color:#fff; }
}

/* --- 50. Paragraph spacing inside nested blocks -----------------------------
   `.prose > * + *` only reaches direct children, so consecutive paragraphs
   inside a .pair__txt or .explore__txt ran together with no gap at all. */
.pair__txt > p + p,
.explore__txt > p + p{ margin-top:var(--s3); }

/* Same cause one level up: the owl selector stops at .case-section, so two
   consecutive paragraphs inside a section ran together with no gap. */
.case-section > p + p,
.case-section > p + ul,
.case-section > p + ol,
.case-section > ul + p,
.case-section > ol + p{ margin-top:var(--s3); }

/* .pair has a top margin but no bottom one, so a paragraph following it sat
   flush against the figure. */
.case-section > .pair + p,
.case-section > .pair + ul,
.case-section > .pair + ol{ margin-top:var(--s5); }

/* --- 51. Embedded prototype, plain well ------------------------------------
   The Quick Buy prototype supplies its own mobile framing, so it gets a light
   well rather than the black device bezel used on case 01 — a phone frame
   round a page that already frames itself is one layer too many. It is a
   mobile-only design, so the well is pinned to the width it was built for. */
.embed__panel{
  width:430px; max-width:100%; margin-inline:auto;
  border:1px solid var(--line); border-radius:16px;
  overflow:hidden; background:var(--paper-2);
}
.embed__panel iframe{ width:100%; height:900px; border:0; display:block; }
@media(max-width:520px){ .embed__panel iframe{ height:760px; } }

/* The Quick Buy prototype uses the plain well rather than the device bezel, so
   the column scaling has to reach that too. Its stage is a little taller than
   case 01's because the prototype carries its own header. */
.mini .embed__panel{
  transform:scale(var(--mini-scale, 1));
  transform-origin:top left;
  margin:0;
}
.mini:has(.embed__panel) .mini__stage{ height:calc(904px * var(--mini-scale, 1)); }

/* --- 52. Test result --------------------------------------------------------
   The A/B numbers were buried in a sentence, where the most consequential fact
   on the page read like an aside. Pulled out, they also give the text column
   something to end on beside a tall prototype. */
.result{
  display:grid; grid-template-columns:1fr 1fr;
  gap:var(--s3) var(--s4);
  margin-top:var(--s5);
}
.result > div{ border-top:2px solid var(--ink); padding-top:.7rem; }
.result dt{ font-size:var(--t-xs); color:var(--muted); margin-bottom:.3rem; }
.result dd{
  font-size:clamp(1.8rem,3.2vw,2.4rem); font-weight:700;
  letter-spacing:-.03em; line-height:1; margin:0;
}

/* --- 53. The tab bar --------------------------------------------------------
   A screenshot of the real thing, at the size it really appears — the point is
   that the difference is only just enough, and blowing it up would flatter it
   into obviousness. */
.tabs{ margin:var(--s4) 0 0; }
.tabs img{ width:100%; max-width:620px; height:auto; }

/* --- 54. Uneven figure row -------------------------------------------------
   A dense UI screenshot needs far more width than a sheet of large elements,
   so the row is split in its favour rather than down the middle. Buttons read
   at a smaller scale than a variables table ever will. */
.ref--uneven{ align-items:start; }
@media(min-width:760px){
  /* 1.7675 is the two images' aspect ratios divided by one another
     (1838:1356 over 1293:1686). Splitting the row by that figure makes both
     render at the same height, and keeps them level at any column width
     rather than only at one. */
  .ref--uneven{ grid-template-columns:1.7675fr 1fr; }
}
.ref--uneven img{ width:100%; height:auto; }

/* --- 55. Kit screenshot on a composed ground --------------------------------
   The screenshot arrived sitting on a dark navy gradient built for the old
   dark site. The panel is cropped out of that and set on a ground composed in
   CSS instead, so the surround follows the page rather than the file — and can
   be changed again without re-exporting anything. */
.kitshot{
  border-radius:16px; overflow:hidden;
  background:linear-gradient(145deg,#E7E7EE 0%,#F3F3F7 48%,#FCFCFD 100%);
  padding:clamp(1.1rem,2.4vw,2rem) 0 0 clamp(1.1rem,2.4vw,2rem);
}
.kitshot img{
  display:block; width:100%; height:auto;
  border:0; background:none;
  border-radius:10px 0 0 0;
  box-shadow:-10px -10px 34px -16px rgba(20,24,40,.22);
}
