/* ============================================================
   ORIGAMI DIGITAL · design system v2 (indigo, nocturnal)
   Per ORIGAMI_DIGITAL_CREATIVE_BRIEF.md · July 2026
   Cool paper, deep ink, one bold fold of indigo. Paper is matte.
   ============================================================ */
:root{
  --paper:#F0EDF5; --paper2:#E5E0ED;
  --ink:#13111E; --ink2:#1E1A2E; --ink3:#2A2440;
  --soft:#6B6580; --soft-dark:#9A92B5;
  --indigo:#53279D; --indigo-d:#371670; --indigo-l:#7C52C7; --indigo-p:#B49CE1;
  --crease:#CDC6D9; --crease-dark:#332C4D;
  --lift:#1F8A5B; --lift-l:#E7F4EE; --lift-dark:#7FD7AC;
  --display:'Chakra Petch','Bai Jamjuree','Segoe UI',Verdana,sans-serif;   /* fold-cut letterforms, chamfered like creased paper */
  --sans:'Bai Jamjuree','Segoe UI',Verdana,Arial,sans-serif;               /* the display face's quieter sibling, same foundry   */
  --mono:'Space Mono',Consolas,'Courier New',monospace;                    /* drafting-table voice for crease markers            */
  --serif:var(--display);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--ink);color:var(--paper);font-family:var(--sans);line-height:1.8;font-size:18px}

/* ---------- navigation ---------- */
.nav{background:var(--ink);border-bottom:1px solid var(--crease-dark);padding:0 28px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:50}
.nav .mark{display:flex;align-items:center;gap:12px;padding:14px 0;text-decoration:none;color:var(--paper)}
.nav .mark svg{width:46px;height:auto;flex:none}
.nav .wm{font-size:18px;letter-spacing:.4px;white-space:nowrap}
.nav .wm b{font-weight:700}.nav .wm span{font-weight:500;color:var(--indigo-p)}
.nav .links{margin-left:auto;display:flex;gap:4px;flex-wrap:wrap}
.nav .links a{color:var(--soft-dark);text-decoration:none;font-size:16px;padding:10px 14px;border-radius:10px;transition:color .15s}
.nav .links a:hover{color:var(--paper)}
.nav .links a.on{color:var(--paper);box-shadow:inset 0 -2px 0 var(--indigo)}

/* ---------- structure ---------- */
.wrap{max-width:920px;margin:0 auto;padding:0 24px}
.section{padding:72px 0}
.section.paper{background:var(--paper);color:var(--ink)}
.section.paper2{background:var(--paper2);color:var(--ink)}
.section.ink2{background:var(--ink2)}

/* the crease · the scroll is the folding sequence */
.creased{position:relative}
.creased::before{content:"";position:absolute;left:50%;top:0;bottom:0;width:1px;background:linear-gradient(180deg,transparent,var(--crease-dark) 8%,var(--crease-dark) 92%,transparent);transform:translateX(-460px);opacity:.6}
@media(max-width:1020px){.creased::before{display:none}}
.foldstep{position:relative}
.foldstep::before{content:attr(data-fold);position:absolute;left:-64px;top:8px;font-family:var(--mono);font-size:12.5px;color:var(--soft);letter-spacing:1px}
@media(max-width:1020px){.foldstep::before{display:none}}

/* ---------- hero ---------- */
.hero{background:var(--ink);position:relative;overflow:hidden;padding:96px 0 84px}
.hero .fold{position:absolute;top:0;right:0;width:300px;height:300px;background:linear-gradient(135deg,var(--indigo-d) 0 50%,transparent 50.5%);opacity:.9}
.hero .fold::after{content:"";position:absolute;top:0;right:0;width:150px;height:150px;background:linear-gradient(135deg,var(--indigo) 0 50%,transparent 50.5%)}
.hero .fold2{position:absolute;bottom:-70px;left:-70px;width:260px;height:260px;background:linear-gradient(315deg,rgba(83,39,157,.14) 0 50%,transparent 50.5%)}
.kicker{letter-spacing:3.5px;font-size:12.5px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:18px;font-family:var(--mono)}
h1{font-family:var(--serif);font-size:46px;line-height:1.18;margin:0 0 18px;font-weight:700;letter-spacing:.2px}
.hero h1{max-width:700px;position:relative;z-index:1}
.hero .sub{color:#B7B1CC;font-size:20px;max-width:640px;margin:0 0 34px;position:relative;z-index:1}
.hero svg.bigcrane{width:200px;height:auto;margin-bottom:30px;position:relative;z-index:1}

/* ---------- type ---------- */
h2{font-family:var(--serif);font-size:32px;line-height:1.25;margin:0 0 10px;position:relative;padding-left:32px;font-weight:700}
h2::before{content:"";position:absolute;left:0;top:13px;width:16px;height:16px;background:linear-gradient(135deg,var(--indigo) 0 50%,var(--indigo-d) 50% 100%);transform:rotate(45deg)}
.section.paper h2,.section.paper2 h2{color:var(--ink)}
h3{font-family:var(--serif);font-size:23px;margin:34px 0 8px;font-weight:700}
.lead{color:var(--soft-dark);margin:0 0 26px;font-size:18px}
.section.paper .lead,.section.paper2 .lead{color:var(--soft)}
p{margin:0 0 18px}
b,strong{color:inherit;font-weight:700}
.section.paper b{color:var(--ink)}
a{color:var(--indigo-l)}
.section.paper a,.section.paper2 a{color:var(--indigo)}

/* ---------- buttons ---------- */
.btn{display:inline-block;background:var(--indigo);color:#fff;text-decoration:none;font-weight:700;font-size:16px;padding:14px 30px;border-radius:10px;position:relative;z-index:1}
.btn:hover{background:var(--indigo-d)}
.btn.ghost{background:transparent;border:1.5px solid var(--crease-dark);color:var(--paper);margin-left:12px}
.btn.ghost:hover{border-color:var(--indigo-l);color:#fff}
.section.paper .btn.ghost{border-color:var(--crease);color:var(--ink)}

/* ---------- cards ---------- */
.cards{display:flex;flex-wrap:wrap;gap:16px;margin:26px 0}
.card{flex:1 1 250px;background:var(--ink2);border:1px solid var(--crease-dark);border-radius:16px;padding:26px 24px}
.section.paper .card,.section.paper2 .card{background:#fff;border-color:var(--crease)}
.card .big{font-family:var(--serif);font-size:40px;font-weight:700;line-height:1.1}
.card .big.lift{color:var(--lift-dark)}
.section.paper .card .big.lift{color:var(--lift)}
.card .big.indigo{color:var(--indigo-l)}
.section.paper .card .big.indigo{color:var(--indigo)}
.card .cap{color:var(--soft-dark);font-size:16px;margin-top:9px;line-height:1.65}
.section.paper .card .cap{color:var(--soft)}

.panel{background:var(--ink2);border:1px solid var(--crease-dark);border-radius:16px;padding:28px 30px;margin:20px 0}
.section.paper .panel,.section.paper2 .panel{background:#fff;border-color:var(--crease)}
.panel.foldcorner{position:relative;overflow:hidden}
.panel.foldcorner::after{content:"";position:absolute;top:0;right:0;width:74px;height:74px;background:linear-gradient(135deg,var(--indigo) 0 50%,transparent 50.5%);opacity:.85}

/* ---------- lists ---------- */
ul.check,ul.next,ul.plain{padding-left:0;margin:16px 0}
.check li{margin:15px 0;list-style:none;position:relative;padding-left:34px}
.check li::before{content:"\2713";position:absolute;left:0;top:0;color:var(--lift-dark);font-weight:700;font-size:18px}
.section.paper .check li::before{color:var(--lift)}
.next li{margin:15px 0;list-style:none;position:relative;padding-left:34px}
.next li::before{content:"\2197";position:absolute;left:0;top:0;color:var(--indigo-l);font-weight:700;font-size:18px}
.plain li{margin:12px 0;list-style:none;position:relative;padding-left:28px}
.plain li::before{content:"";position:absolute;left:2px;top:11px;width:9px;height:9px;background:var(--indigo);transform:rotate(45deg)}

/* ---------- tables ---------- */
table{width:100%;border-collapse:collapse;font-size:18px}
th{text-align:left;color:var(--soft);font-weight:600;font-size:14.5px;text-transform:uppercase;letter-spacing:1px;padding:0 16px 12px 0;border-bottom:2px solid var(--crease)}
td{padding:12px 16px 12px 0;border-bottom:1px solid var(--paper2);vertical-align:top}
tr:last-child td{border-bottom:none}
.dark-table th{border-color:var(--crease-dark);color:var(--soft-dark)}
.dark-table td{border-color:var(--crease-dark)}

/* ---------- brand band ---------- */
.brandband{padding:20px 28px;background:var(--ink2);border:1px solid var(--crease-dark);color:var(--paper);border-radius:16px;font-family:var(--serif);font-size:24px;font-weight:700;position:relative;overflow:hidden;margin:30px 0 8px}
.brandband::after{content:"";position:absolute;top:0;right:0;width:92px;height:92px;background:linear-gradient(135deg,var(--indigo) 0 50%,transparent 50.5%)}
.brandband small{display:block;font-family:var(--sans);font-weight:400;font-size:14.5px;color:var(--soft-dark);margin-top:4px}

/* ---------- case study meta strip ---------- */
.meta{display:flex;flex-wrap:wrap;gap:26px;font-family:var(--mono);font-size:14.5px;color:var(--soft-dark);margin:6px 0 20px}
.meta span b{color:var(--paper);font-family:var(--sans)}
.section.paper .meta{color:var(--soft)}
.section.paper .meta span b{color:var(--ink)}

/* ---------- stat rows / evidence bars ---------- */
.bars .brow{display:flex;align-items:center;gap:14px;margin:14px 0}
.bars .blabel{flex:0 0 200px;font-size:16px;color:var(--soft);line-height:1.4}
.bars .btrack{flex:1;background:var(--paper2);border-radius:999px;height:32px;overflow:hidden}
.bars .bfill{height:100%;border-radius:999px;display:flex;align-items:center;justify-content:flex-end;padding:0 12px;font-weight:700;font-size:14.5px;color:#fff;min-width:64px}
.bars .bfill.ink{background:linear-gradient(90deg,var(--ink3),var(--ink))}
.bars .bfill.indigo{background:linear-gradient(90deg,var(--indigo-l),var(--indigo-d))}
.bars .bfill.lift{background:linear-gradient(90deg,#2EA873,#177049)}

/* ---------- quote / self-reference ---------- */
.selfref{border-left:5px solid var(--indigo);padding:20px 26px;background:var(--ink2);border-radius:0 14px 14px 0;margin:26px 0;font-family:var(--serif);font-size:20px;line-height:1.7}
.section.paper .selfref{background:#fff;border:1px solid var(--crease);border-left:5px solid var(--indigo)}

/* ---------- footer ---------- */
.foot{background:var(--ink);border-top:1px solid var(--crease-dark);padding:44px 28px 54px}
.foot .inner{max-width:920px;margin:0 auto;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.foot svg{width:48px;height:auto}
.foot .l{font-size:16px;color:var(--soft-dark);line-height:1.7}
.foot .l b{color:var(--paper)}
.foot .r{margin-left:auto;font-size:14.5px;color:var(--soft);text-align:right;line-height:1.7}
.foot a{color:var(--indigo-p);text-decoration:none}

/* ---------- misc ---------- */
.pill{display:inline-block;background:var(--lift-l);color:var(--lift);border-radius:999px;font-size:12.5px;font-weight:700;padding:2px 12px;white-space:nowrap}
.pill.indigo{background:#EAE3F8;color:var(--indigo-d)}
.mono{font-family:var(--mono)}
.center{text-align:center}
hr.crease{border:none;border-top:1px solid var(--crease);margin:36px 0}
@media(max-width:720px){
  h1{font-size:32px} h2{font-size:24px}
  .hero{padding:64px 0 56px}
  .nav{padding:0 16px}
  .nav .links a{padding:10px 8px;font-size:14.5px}
  .bars .blabel{flex:0 0 120px;font-size:14.5px}
}
@media print{body{background:#fff}}

/* ============================================================
   v3 · THE FOLD VOCABULARY - bespoke origami components
   ============================================================ */

/* authentic crease-pattern texture: solid = mountain fold, dashed = valley fold */
.cpbg{position:relative}
.cpbg > *{position:relative;z-index:1}
.cpbg::before{content:"";position:absolute;inset:0;pointer-events:none;opacity:.055;z-index:0;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cpath d='M0 180L180 0' stroke='%23B49CE1' stroke-width='1'/%3E%3Cpath d='M0 0L180 180' stroke='%23B49CE1' stroke-width='1' stroke-dasharray='6 8'/%3E%3Cpath d='M90 0L90 180' stroke='%23B49CE1' stroke-width='.6' stroke-dasharray='3 10'/%3E%3C/svg%3E")}

/* folded section transitions: each section's top edge is a diagonal crease */
.tilt{clip-path:polygon(0 0,100% 52px,100% 100%,0 100%);margin-top:-52px;padding-top:calc(72px + 52px)}
.tilt.alt{clip-path:polygon(0 52px,100% 0,100% 100%,0 100%)}
@media(max-width:720px){.tilt,.tilt.alt{clip-path:polygon(0 0,100% 26px,100% 100%,0 100%);margin-top:-26px;padding-top:calc(56px + 26px)}}

/* the workbench: stat tags as folded, dog-eared sheets of paper */
.bench{display:flex;flex-wrap:wrap;gap:24px;margin:34px 0 8px}
.sheet{flex:1 1 230px;min-height:150px;position:relative;color:var(--ink);border-radius:6px;
  background:linear-gradient(118deg,#FCFBFE 0 62%,#ECE7F4 62% 100%);
  padding:22px 24px 18px;clip-path:polygon(0 0,calc(100% - 32px) 0,100% 32px,100% 100%,0 100%);
  box-shadow:0 14px 30px rgba(0,0,0,.45)}
.sheet::before{content:"";position:absolute;top:0;right:0;width:32px;height:32px;
  background:linear-gradient(225deg,transparent 0 50%,var(--indigo-p) 50% 100%)}
.sheet .n{font-family:var(--display);font-size:38px;font-weight:700;color:var(--indigo-d);line-height:1.05}
.sheet .n.lift{color:var(--lift)}
.sheet .c{font-size:14.5px;color:#4A445E;margin-top:7px;line-height:1.55}
.sheet a{display:inline-block;margin-top:10px;font-family:var(--mono);font-size:12.5px;letter-spacing:1px;color:var(--indigo);text-decoration:none;text-transform:uppercase}
.sheet a:hover{color:var(--indigo-d)}
.sheet:nth-child(odd){transform:rotate(-1.4deg)}
.sheet:nth-child(even){transform:rotate(1.1deg)}
.sheet:hover{transform:rotate(0deg)}
.sheet.onpaper{box-shadow:0 10px 22px rgba(26,31,53,.16)}
.sheet .k{font-family:var(--mono);font-size:12.5px;letter-spacing:2.5px;color:var(--indigo);text-transform:uppercase;margin-bottom:8px}

/* the sheet-to-flight strip: flat square, first crease, the base, the crane */
.unfold{display:flex;flex-wrap:wrap;align-items:flex-end;gap:8px;margin:36px 0 6px;justify-content:space-between}
.stage{flex:1 1 150px;text-align:center;position:relative}
.stage svg{width:104px;height:104px;display:block;margin:0 auto 12px}
.stage .cap{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;color:var(--soft-dark);text-transform:uppercase}
.stage .cap b{display:block;color:var(--indigo-p);font-size:12.5px;margin-bottom:3px}
.joint{flex:0 0 34px;align-self:center;border-top:2px dashed var(--crease-dark);margin-bottom:44px}
@media(max-width:720px){.joint{display:none}}

/* paper left flat: the folds refused */
.flats{display:flex;flex-wrap:wrap;gap:18px;margin:28px 0 6px}
.flat{flex:1 1 250px;border:1.6px dashed var(--crease-dark);border-radius:10px;padding:20px 22px;background:rgba(255,255,255,.025);color:var(--soft-dark)}
.flat b{display:block;font-family:var(--display);letter-spacing:.4px;color:var(--paper);margin-bottom:6px;font-size:18px}
.flat .no{font-family:var(--mono);font-size:11px;letter-spacing:2px;color:var(--soft);text-transform:uppercase;display:block;margin-bottom:8px}
.flat p{margin:0;font-size:16px;line-height:1.65}

/* the envelope: contact as an opened fold */
.env{position:relative;max-width:660px;margin:26px auto 0;background:linear-gradient(180deg,var(--ink2),#26203C);border:1px solid var(--crease-dark);border-radius:16px;padding:96px 36px 36px}
.env::before{content:"";position:absolute;top:0;left:0;width:50.4%;height:80px;border-radius:16px 0 0 0;
  background:linear-gradient(to bottom right,var(--indigo-d) 0 49.5%,transparent 50%)}
.env::after{content:"";position:absolute;top:0;right:0;width:50.4%;height:80px;border-radius:0 14px 0 0;
  background:linear-gradient(to bottom left,var(--indigo) 0 49.5%,transparent 50%)}
.env .letter{background:#FCFBFE;color:var(--ink);border-radius:6px;padding:26px 28px;box-shadow:0 12px 28px rgba(0,0,0,.4);position:relative;clip-path:polygon(0 0,calc(100% - 26px) 0,100% 26px,100% 100%,0 100%)}
.env .letter::before{content:"";position:absolute;top:0;right:0;width:26px;height:26px;background:linear-gradient(225deg,transparent 0 50%,var(--indigo-p) 50% 100%)}
.env .letter p{color:#3A3450;font-size:16px;margin:0 0 18px}
.env .letter .from{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;color:var(--indigo);text-transform:uppercase;margin-bottom:10px}

/* sheet-vs-crane comparison row */
.compare{display:flex;align-items:center;gap:26px;flex-wrap:wrap;margin:30px 0 10px;justify-content:center}
.compare .side{text-align:center;flex:0 1 220px}
.compare .side svg{width:130px;height:110px;display:block;margin:0 auto 10px}
.compare .side .cap{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;text-transform:uppercase;color:var(--soft)}
.compare .arrowjoint{flex:0 0 60px;border-top:2px dashed var(--crease);position:relative;align-self:center}
.compare .arrowjoint::after{content:"";position:absolute;right:-2px;top:-6px;width:10px;height:10px;border-top:2px dashed var(--crease);border-right:2px dashed var(--crease);transform:rotate(45deg)}

/* ============================================================
   v4 · MOTION + ATMOSPHERE
   ============================================================ */
.rv{opacity:0;transform:perspective(1000px) rotateX(-12deg) translateY(24px);transform-origin:top center;transition:opacity .7s ease,transform .85s cubic-bezier(.2,.7,.25,1)}
.rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none}}

.sheet{transition:transform .35s ease,box-shadow .35s ease}
.sheet:hover{transform:rotate(0deg) translateY(-8px);box-shadow:0 24px 48px rgba(0,0,0,.5)}
.sheet.onpaper:hover{box-shadow:0 18px 36px rgba(19,17,30,.22)}
.btn{transition:transform .25s ease,background .2s ease,border-color .2s ease}
.btn:hover{transform:translateY(-2px)}
.nav .links a{transition:color .15s ease,box-shadow .25s ease}

@keyframes cpdrift{from{background-position:0 0}to{background-position:180px 180px}}
.cpbg::before{animation:cpdrift 90s linear infinite}

/* crane assembles facet by facet on load */
.bigcrane polygon{opacity:0;animation:facet .6s ease forwards}
.bigcrane polygon:nth-child(1){animation-delay:.08s}
.bigcrane polygon:nth-child(2){animation-delay:.18s}
.bigcrane polygon:nth-child(3){animation-delay:.28s}
.bigcrane polygon:nth-child(4){animation-delay:.38s}
.bigcrane polygon:nth-child(5){animation-delay:.48s}
.bigcrane polygon:nth-child(6){animation-delay:.58s}
.bigcrane polygon:nth-child(7){animation-delay:.74s}
@keyframes facet{to{opacity:1}}

/* hero copy staggers in */
.hero .kicker,.hero h1,.hero .sub,.hero .btn{opacity:0;transform:translateY(18px);animation:heroin .8s ease forwards}
.hero .kicker{animation-delay:.2s}
.hero h1{animation-delay:.35s}
.hero .sub{animation-delay:.55s}
.hero .btn{animation-delay:.7s}
.hero .btn.ghost{animation-delay:.82s}
@keyframes heroin{to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.bigcrane polygon,.hero .kicker,.hero h1,.hero .sub,.hero .btn{opacity:1;animation:none;transform:none}}

/* nocturnal atmosphere on ink sections */
main > .section:not(.paper):not(.paper2){background:radial-gradient(1100px 560px at 82% -8%,#1E1734 0%,var(--ink) 58%)}

/* ghost crane watermark (svg only - must not touch .btn.ghost buttons) */
svg.ghost{position:absolute;right:-150px;bottom:-70px;width:600px;height:auto;opacity:.05;pointer-events:none;z-index:0}
.hasghost{position:relative;overflow:hidden}
.hasghost .wrap{position:relative;z-index:1}

/* pattern step chips */
.patsteps{display:flex;flex-wrap:wrap;gap:14px;margin:28px 0 8px}
.pstep{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;text-transform:uppercase;color:var(--soft-dark);border:1px solid var(--crease-dark);border-radius:999px;padding:11px 20px;background:rgba(255,255,255,.02)}
.pstep b{color:var(--indigo-p);margin-right:8px}

/* sheet aliases so interior stat cards convert cleanly */
.sheet .big{font-family:var(--display);font-size:32px;font-weight:700;color:var(--indigo-d);line-height:1.1}
.sheet .big.lift{color:var(--lift)}
.sheet .big.indigo{color:var(--indigo-d)}
.sheet .cap{font-size:14.5px;color:#4A445E;margin-top:7px;line-height:1.55}
.sheet .stars{font-size:20px}

/* ============================================================
   v5 · MATERIALITY LAYER - paper, wood, ink made physical
   Per ORIGAMI_VISUAL_GUIDE.md · July 2026
   The site now lives on a desk, under a lamp, at 2 AM.
   ============================================================ */

/* ---------- home hero: the photograph IS the crane (homepage only) ---------- */
.homehero::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    linear-gradient(96deg, var(--ink) 3%, rgba(19,17,30,.88) 28%, rgba(19,17,30,.40) 58%, rgba(19,17,30,.20) 78%, rgba(19,17,30,.55) 100%),
    linear-gradient(180deg, rgba(19,17,30,.55) 0%, transparent 16%, transparent 80%, var(--ink) 100%),
    url("img/hero-crane.jpg");
  background-size:cover,cover,auto 120%;
  background-position:center,center,84% calc(42% + var(--hpar,0px));
  background-repeat:no-repeat}
.homehero .wrap{position:relative;z-index:2}
.homehero .bigcrane{display:none}          /* retired - the photograph carries it */
.homehero .fold{display:none}              /* top-right corner would sit on the crane */
.homehero .fold2{z-index:1;opacity:.7}
.homehero .sub{color:#C4BED8}
@media(max-width:760px){
  /* crane becomes a faint atmospheric ghost so text stays fully legible */
  .homehero.cine::after{
    background:
      linear-gradient(180deg, rgba(19,17,30,.90) 0%, rgba(19,17,30,.80) 44%, rgba(19,17,30,.72) 70%, rgba(19,17,30,.88) 100%),
      url("img/hero-crane.jpg");
    background-size:cover, cover;
    background-position:center, 68% 64%;
    background-repeat:no-repeat}
  .homehero.cine{min-height:88vh;padding:64px 0 76px}
  .homehero.cine .kicker{letter-spacing:2.5px;font-size:11px}
  .homehero.cine .sub{margin-bottom:28px}
  .hero .cta-row{gap:10px}
  .hero .cta-row .btn{flex:1 1 auto;text-align:center}
}
/* interior page heroes: a subtle nocturnal deepening, kept typographic */
.hero.cpbg:not(.homehero){background:radial-gradient(1200px 520px at 82% -12%,#221A3C 0%,var(--ink) 60%)}

/* ---------- the workbench: paper stats on real wood ---------- */
.desk{position:relative;border-radius:16px;padding:34px 30px 28px;margin:34px 0 8px;overflow:hidden;
  background:linear-gradient(rgba(19,17,30,.50),rgba(19,17,30,.66)),url("img/workbench.jpg") center/cover;
  box-shadow:inset 0 0 100px rgba(0,0,0,.72), 0 22px 54px rgba(0,0,0,.5)}
.desk::after{content:"";position:absolute;inset:0;pointer-events:none;border-radius:16px;
  box-shadow:inset 0 1px 0 rgba(180,156,225,.06)}
.desk .bench{margin:0 0 18px}
.desk .bench:last-child{margin-bottom:0}
.desk .sheet{box-shadow:0 16px 36px rgba(0,0,0,.6)}
.desk .sheet:hover{box-shadow:0 26px 52px rgba(0,0,0,.68)}

/* ---------- paper sections: real fibre, felt not seen ---------- */
.section.paper,.section.paper2{position:relative}
.section.paper::before,.section.paper2::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:url("img/paper-fiber.jpg");background-size:540px;opacity:.05;mix-blend-mode:multiply}
.section.paper > *,.section.paper2 > *{position:relative;z-index:1}
/* the paper is pulled out of shadow at the top crease */
.section.paper.tilt::after,.section.paper2.tilt::after{content:"";position:absolute;left:0;right:0;top:0;height:120px;z-index:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(19,17,30,.22),transparent)}

/* ---------- evidence frame: real data, branded, laid on the desk ---------- */
.evidence{background:var(--ink2);border:1px solid var(--crease-dark);border-radius:16px;padding:16px;position:relative;overflow:hidden;
  transform:rotate(-0.8deg);transition:transform .35s ease;max-width:560px;margin:26px auto}
.evidence::after{content:"";position:absolute;top:0;right:0;width:54px;height:54px;
  background:linear-gradient(135deg,var(--indigo) 0 50%,transparent 50.5%);opacity:.85}
.evidence img{width:100%;border-radius:10px;display:block}
.evidence .source{font-family:var(--mono);font-size:12.5px;letter-spacing:1.5px;color:var(--soft-dark);text-transform:uppercase;margin-top:12px}
.evidence:hover{transform:rotate(0deg)}

/* ---------- section accent photographs ---------- */
.accent{border-radius:10px;overflow:hidden;position:relative;box-shadow:0 18px 40px rgba(0,0,0,.5)}
.accent img{display:block;width:100%;height:auto}
.accentband img,.workshop .accent img{height:100%;object-fit:cover}
.accent::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 60%,rgba(19,17,30,.35));pointer-events:none}
/* float-right accent that text wraps around */
.accent.float{float:right;width:300px;margin:6px 0 20px 32px}
@media(max-width:720px){.accent.float{float:none;width:100%;margin:16px 0}}
/* full-width band accent (case study heroes) */
.accentband{width:100%;max-height:340px;border-radius:16px;margin:6px 0 24px}
.accentband img{width:100%;height:340px;object-fit:cover;display:block}

/* the folded-paper split for About (hands at the bench) */
.workshop{display:grid;grid-template-columns:1fr 1fr;gap:30px;align-items:center;margin:28px 0}
.workshop .accent{height:100%;min-height:320px}
@media(max-width:760px){.workshop{grid-template-columns:1fr}}

/* ---------- image reveal: uncovered, not moved · CSS-driven so an image can never strand invisible ---------- */
.imgrv{opacity:0;animation:imgin .9s ease .15s forwards}
.imgrv.in{opacity:1}
@keyframes imgin{to{opacity:1}}
@media(prefers-reduced-motion:reduce){.imgrv{opacity:1;animation:none}}

/* ---------- interior hero atmospheres ---------- */
.hero.broken::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:linear-gradient(rgba(19,17,30,.80),rgba(19,17,30,.90)),url("img/crumple-dark.jpg") center/cover}
.hero.broken .wrap{position:relative;z-index:2}
.hero.folds::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:linear-gradient(96deg,var(--ink) 6%,rgba(19,17,30,.78) 34%,rgba(19,17,30,.42) 66%,rgba(19,17,30,.62) 100%),url("img/cranes-flight.jpg") right center/cover no-repeat}
.hero.folds .wrap{position:relative;z-index:2}
.hero.folds .fold{display:none}

/* ============================================================
   v6 · CINEMATIC-KINETIC - the showpiece layer
   Full-bleed moody scenes (cinematic) driven by massive display
   type, bold indigo, depth and scroll motion (kinetic bold agency).
   Between "1 and 2". Homepage-first vocabulary; reused site-wide.
   ============================================================ */

/* full-bleed sections - already full-width as direct children of main,
   so width:100% avoids the 100vw-vs-scrollbar horizontal overflow */
.bleed{position:relative;width:100%}
/* guard horizontal overflow WITHOUT breaking position:sticky (overflow-x:clip on
   html/body kills sticky descendants in Chrome) - clip decorative overflow locally instead */
.hero,.markets,.statement,.finalcta{overflow-x:clip}
.wide{max-width:1240px;margin:0 auto;padding:0 32px}
.wider{max-width:1440px;margin:0 auto;padding:0 40px}
@media(max-width:720px){.wide,.wider{padding:0 20px}}

/* kinetic word reveal - JS splits text into .kw spans, sets --d per word */
.kinetic .kw{display:inline-block;opacity:0;transform:translateY(.5em) rotate(2deg);
  animation:kwin .78s cubic-bezier(.16,.9,.24,1) forwards;animation-delay:var(--d,0s)}
@keyframes kwin{to{opacity:1;transform:none}}
.kinetic.onview .kw{animation-play-state:paused}
.kinetic.onview.go .kw{animation-play-state:running}
@media(prefers-reduced-motion:reduce){.kinetic .kw{opacity:1;transform:none;animation:none}}

/* ---------- CINEMATIC HERO ---------- */
.homehero.cine{min-height:90vh;display:flex;align-items:center;padding:88px 0 92px}
.homehero.cine::before{opacity:.04}
.homehero.cine .wrap{max-width:1240px;padding:0 32px;width:100%}
.homehero.cine .kicker{font-size:12.5px;letter-spacing:5px;margin-bottom:26px;color:var(--indigo-p)}
.hero h1.mega{font-size:clamp(44px,6.4vw,104px);line-height:1.0;letter-spacing:-1.5px;
  max-width:19ch;margin:0 0 22px;font-weight:700;text-shadow:0 8px 40px rgba(0,0,0,.4)}
.hero h1.mega em{font-style:normal;color:var(--indigo-p)}
.homehero.cine .sub{font-size:clamp(17px,1.5vw,21px);max-width:600px;color:#C9C3DC;margin-bottom:38px}
.hero .cta-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.hero .btn.big{font-size:18px;padding:17px 38px}
.herometa{position:absolute;left:0;right:0;bottom:0;z-index:3;border-top:1px solid rgba(180,156,225,.16);
  background:linear-gradient(rgba(19,17,30,0),rgba(19,17,30,.5))}
.herometa .in{max-width:1240px;margin:0 auto;padding:16px 32px;display:flex;gap:30px;flex-wrap:wrap;
  font-family:var(--mono);font-size:12.5px;letter-spacing:2.5px;text-transform:uppercase;color:var(--soft-dark)}
.herometa .in b{color:var(--indigo-p);font-weight:400}
.herometa .in .sep{color:var(--crease-dark)}
.scrollcue{position:absolute;left:50%;bottom:82px;transform:translateX(-50%);z-index:3;
  font-family:var(--mono);font-size:11px;letter-spacing:3px;color:var(--soft-dark);text-transform:uppercase;
  writing-mode:vertical-rl;display:flex;align-items:center;gap:12px}
.scrollcue::after{content:"";width:1px;height:46px;background:linear-gradient(var(--indigo-p),transparent);animation:cuepulse 2.2s ease-in-out infinite}
@keyframes cuepulse{0%,100%{opacity:.3;transform:scaleY(.6)}50%{opacity:1;transform:scaleY(1)}}
@media(max-width:820px){
  .scrollcue{display:none}
  /* static below the CTAs so the meta strip can never overlap them on small screens */
  .herometa{position:static;margin-top:44px;background:none;width:100%}
  .herometa .in{gap:10px 16px;font-size:11px;padding:14px 32px 0}
  .herometa .in .sep{display:none}
  .homehero.cine{flex-direction:column;align-items:stretch;justify-content:center;padding-bottom:56px}
}

/* ---------- THE STATEMENT - giant typographic scene ---------- */
.statement{background:var(--ink);padding:clamp(90px,15vh,180px) 0;position:relative;overflow:hidden}
.statement::before{content:"";position:absolute;inset:0;opacity:.05;pointer-events:none;
  background:url("img/paper-fiber.jpg") center/620px;mix-blend-mode:screen}
.statement .big{font-family:var(--display);font-weight:700;font-size:clamp(34px,5.4vw,78px);
  line-height:1.06;letter-spacing:-.5px;max-width:17ch;margin:0}
.statement .big .hi{color:var(--indigo-l)}
.statement .big .go2{color:var(--indigo-p)}
.statement .foot-note{margin-top:34px;font-family:var(--mono);font-size:12.5px;letter-spacing:1px;color:var(--soft-dark);max-width:52ch}

/* ---------- THE FIGURES - giant numbers on real wood ---------- */
.figures{position:relative;padding:0}
.figures .deskwood{position:relative;overflow:hidden;
  background:linear-gradient(rgba(19,17,30,.62),rgba(19,17,30,.74)),url("img/workbench.jpg") center/cover;
  box-shadow:inset 0 0 160px rgba(0,0,0,.8)}
.figures .inner{max-width:1240px;margin:0 auto;padding:clamp(64px,9vh,110px) 32px}
.figures .eyebrow{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:8px}
.figures h2.plainh{font-size:clamp(29px,3.8vw,50px);padding-left:0;margin:0 0 6px;max-width:20ch}
.figures h2.plainh::before{display:none}
.figures .fnote{color:var(--soft-dark);font-size:16px;max-width:56ch;margin:0 0 48px}
.figgrid{display:grid;grid-template-columns:repeat(6,1fr);gap:40px 34px}
.figure{position:relative}
.figure.s2{grid-column:span 2}.figure.s3{grid-column:span 3}
.figure .fig-n{font-family:var(--display);font-weight:700;line-height:.92;letter-spacing:-2px;
  font-size:clamp(44px,6.4vw,104px);color:var(--paper);display:block}
.figure .fig-n.lift{color:var(--lift-dark)}
.figure .fig-n.indigo{color:var(--indigo-p)}
.figure .fig-k{font-family:var(--mono);font-size:12.5px;letter-spacing:2.5px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:14px;display:block}
.figure .fig-c{color:#C9C3DC;font-size:16px;line-height:1.55;margin-top:12px;max-width:34ch;
  border-top:1px solid rgba(180,156,225,.2);padding-top:12px}
.figure a{display:inline-block;margin-top:10px;font-family:var(--mono);font-size:12.5px;letter-spacing:1.5px;
  text-transform:uppercase;color:var(--indigo-p);text-decoration:none}
.figure a:hover{color:var(--paper)}
@media(max-width:900px){.figgrid{grid-template-columns:1fr 1fr;gap:34px 26px}.figure.s2,.figure.s3{grid-column:span 1}}
@media(max-width:560px){.figgrid{grid-template-columns:1fr}}

/* ---------- THREE MARKETS - cinematic bold panels ---------- */
.markets{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;background:var(--crease-dark)}
.market{position:relative;min-height:clamp(380px,54vh,560px);overflow:hidden;display:flex;flex-direction:column;justify-content:flex-end;
  padding:38px 32px;text-decoration:none;color:var(--paper);isolation:isolate}
.market .bgimg{position:absolute;inset:0;z-index:-2;background-size:cover;background-position:center;transition:transform 1.1s cubic-bezier(.2,.7,.2,1)}
.market::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(19,17,30,.30) 0%,rgba(19,17,30,.55) 46%,rgba(19,17,30,.92) 100%)}
.market:hover .bgimg{transform:scale(1.07)}
.market .mnum{font-family:var(--mono);font-size:12.5px;letter-spacing:3px;color:var(--indigo-p);margin-bottom:auto}
.market .mcity{font-family:var(--display);font-weight:700;font-size:clamp(26px,2.6vw,40px);line-height:1.02;margin:0 0 6px;letter-spacing:-.5px}
.market .mtag{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:14px}
.market .mdesc{color:#CFC9DF;font-size:16px;line-height:1.6;max-width:36ch;margin:0 0 16px}
.market .mgo{font-family:var(--mono);font-size:12.5px;letter-spacing:1.5px;text-transform:uppercase;color:var(--paper);
  border-top:1px solid rgba(180,156,225,.3);padding-top:14px;display:inline-flex;gap:8px}
.market:hover .mgo{color:var(--indigo-p)}
.market .mbar{position:absolute;left:0;top:0;height:4px;width:0;background:var(--indigo);transition:width .5s ease;z-index:1}
.market:hover .mbar{width:100%}
@media(max-width:820px){.markets{grid-template-columns:1fr}.market{min-height:340px}}

/* ---------- REAL PROOF - the evidence moment, cinematic ---------- */
.proof{background:radial-gradient(1200px 700px at 78% 0%,#1E1734,var(--ink) 62%);padding:clamp(80px,12vh,140px) 0;position:relative;overflow:hidden}
.proof .grid{max-width:1240px;margin:0 auto;padding:0 32px;display:grid;grid-template-columns:1fr 1.05fr;gap:60px;align-items:center}
.proof .eyebrow{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:20px}
.proof h2.big{font-size:clamp(34px,4.6vw,62px);line-height:1.02;letter-spacing:-1px;padding-left:0;margin:0 0 22px}
.proof h2.big::before{display:none}
.proof h2.big em{font-style:normal;color:var(--lift-dark)}
.proof p.say{color:#C9C3DC;font-size:18px;max-width:44ch;margin:0 0 30px}
.proof .kpis{display:flex;flex-wrap:wrap;gap:14px}
.proof .kpi{background:rgba(30,23,52,.6);border:1px solid var(--crease-dark);border-radius:10px;padding:16px 20px;min-width:130px}
.proof .kpi .v{font-family:var(--display);font-weight:700;font-size:32px;line-height:1;color:var(--paper)}
.proof .kpi .v.lift{color:var(--lift-dark)}
.proof .kpi .l{font-family:var(--mono);font-size:11px;letter-spacing:1.5px;text-transform:uppercase;color:var(--soft-dark);margin-top:8px}
.proof .shot{position:relative}
.proof .shot .frame{background:#F4F2F8;border-radius:16px;padding:10px;box-shadow:0 34px 70px rgba(0,0,0,.6);transform:rotate(1.1deg);transition:transform .5s ease}
.proof .shot:hover .frame{transform:rotate(0)}
.proof .shot .frame img{width:100%;display:block;border-radius:10px}
.proof .shot .tag{position:absolute;left:-14px;top:-14px;background:var(--indigo);color:#fff;font-family:var(--mono);font-size:11px;letter-spacing:1.5px;text-transform:uppercase;padding:8px 14px;border-radius:10px;box-shadow:0 10px 24px rgba(0,0,0,.4);z-index:2}
.proof .shot .src{font-family:var(--mono);font-size:12.5px;letter-spacing:1px;color:var(--soft-dark);text-align:right;margin-top:12px}
@media(max-width:860px){.proof .grid{grid-template-columns:1fr;gap:40px}}

/* ---------- METHOD teaser, bolder diagonal ---------- */
.methodtease{background:var(--ink2);position:relative;overflow:hidden;padding:clamp(70px,10vh,120px) 0;
  clip-path:polygon(0 40px,100% 0,100% 100%,0 100%)}
.methodtease .wide{position:relative;z-index:1}
.methodtease .eyebrow{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:12px}
.methodtease h2{font-size:clamp(29px,3.8vw,50px);padding-left:0;margin:0 0 8px}
.methodtease h2::before{display:none}
.foldrow{display:grid;grid-template-columns:repeat(4,1fr);gap:24px;margin:44px 0 8px}
.foldcard{position:relative;padding:26px 22px 24px;border:1px solid var(--crease-dark);border-radius:10px;background:rgba(255,255,255,.02);overflow:hidden;transition:transform .4s ease,border-color .3s}
.foldcard::before{content:"";position:absolute;top:0;right:0;width:44px;height:44px;background:linear-gradient(135deg,var(--indigo) 0 50%,transparent 50.5%);opacity:.6;transition:opacity .3s}
.foldcard:hover{transform:translateY(-6px);border-color:var(--indigo-l)}
.foldcard:hover::before{opacity:1}
.foldcard .fn{font-family:var(--display);font-weight:700;font-size:52px;line-height:1;color:var(--indigo-l);opacity:.85}
.foldcard .ft{font-family:var(--display);font-weight:700;font-size:18px;margin:14px 0 6px;color:var(--paper)}
.foldcard .fd{font-size:14.5px;color:var(--soft-dark);line-height:1.6;margin:0}
@media(max-width:820px){.foldrow{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.foldrow{grid-template-columns:1fr}}

/* ---------- REFUSED FOLDS, bolder ---------- */
.refused{padding:clamp(70px,10vh,120px) 0}
.refused h2{font-size:clamp(29px,3.8vw,50px)}
.refused .flats{gap:20px}
.refused .flat{background:rgba(255,255,255,.02);transition:border-color .3s,transform .3s}
.refused .flat:hover{border-color:var(--indigo-l);transform:translateY(-4px)}
.refused .flat b{font-size:18px}

/* ---------- final CTA, cinematic ---------- */
.finalcta{position:relative;overflow:hidden;padding:clamp(90px,13vh,150px) 0;text-align:center;
  background:linear-gradient(rgba(19,17,30,.74),rgba(19,17,30,.9)),url("img/crumple-indigo.jpg") center/cover}
.finalcta h2{font-size:clamp(34px,5.4vw,78px);line-height:1;letter-spacing:-1px;padding-left:0;margin:0 auto 18px;max-width:16ch;text-align:center}
.finalcta h2::before{display:none}
.finalcta p{color:#C9C3DC;font-size:18px;max-width:46ch;margin:0 auto 34px}
.finalcta .btn.big{font-size:18px;padding:18px 44px}

.kinetic .kw.hi{color:var(--indigo-p)}
.statement .kinetic .kw.hi{color:var(--indigo-l)}

/* ============================================================
   v7 · REFINEMENT PASS - alignment, graphics, real cities,
   animated proof gallery. Awwwards discipline on every detail.
   ============================================================ */

/* ---------- HERO: text lives on the dark wall, crane on the light side ---------- */
.homehero.cine::after{
  background:
    linear-gradient(90deg, var(--ink) 0%, var(--ink) 32%, rgba(19,17,30,.90) 48%, rgba(19,17,30,.42) 66%, rgba(19,17,30,.28) 82%, rgba(19,17,30,.52) 100%),
    linear-gradient(180deg, rgba(19,17,30,.55) 0%, transparent 18%, transparent 76%, var(--ink) 100%),
    url("img/hero-crane.jpg");
  background-size:cover,cover,auto 118%;
  background-position:center,center,90% calc(45% + var(--hpar,0px));
  background-repeat:no-repeat;
}
.homehero.cine .wrap{max-width:1280px}
.hero .herocol{max-width:600px}          /* everything hangs off the left gutter */
.hero h1.mega{font-size:clamp(34px,5.4vw,78px);max-width:15ch;line-height:1.03}
.hero .herocol{max-width:660px}
.homehero.cine .kicker,.homehero.cine .sub,.hero .cta-row{text-align:left}
@media(max-width:820px){
  .hero .herocol{max-width:100%}
  .hero h1.mega{max-width:16ch}
}

/* ---------- THE STATEMENT: graphic fill + brighter aligned subtext ---------- */
.statement .wide{position:relative;z-index:1}
.statement .smark{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p);margin:0 0 24px;display:flex;align-items:center;gap:14px}
.statement .smark::after{content:"";flex:1;max-width:120px;height:1px;background:linear-gradient(90deg,var(--indigo),transparent)}
.statement .big{max-width:19ch}
.statement .foot-note{margin-top:36px;font-family:var(--sans);font-size:16px;letter-spacing:0;color:#C4BEDA;max-width:56ch;line-height:1.7;padding-left:20px;border-left:2px solid var(--indigo)}
.statement .foot-note b{color:var(--indigo-p)}
/* the crease-pattern diagram, drawn on the right, drifting */
.creasegraphic{position:absolute;right:-70px;top:50%;transform:translateY(-50%);width:min(40vw,500px);height:auto;opacity:.38;pointer-events:none;z-index:0}
.statement .big{max-width:17ch}
.creasegraphic path,.creasegraphic line{stroke:var(--indigo-l);fill:none;vector-effect:non-scaling-stroke}
.creasegraphic .val{stroke:var(--indigo-p);stroke-dasharray:5 7;opacity:.7}
.creasegraphic .mtn{stroke:var(--indigo-l);opacity:.85}
.creasegraphic .draw{stroke-dasharray:var(--len,1400);stroke-dashoffset:var(--len,1400)}
.creasegraphic.drawing .draw{animation:drawline 3.2s ease forwards}
@keyframes drawline{to{stroke-dashoffset:0}}
@media(max-width:900px){.creasegraphic{display:none}}
@media(prefers-reduced-motion:reduce){.creasegraphic .draw,.creasegraphic.drawing .draw{animation:none;stroke-dashoffset:0}}

/* ---------- FIGURES: sharper hierarchy, accent, motion ---------- */
.figures .eyebrow{display:flex;align-items:center;gap:14px}
.figures .eyebrow::after{content:"";flex:0 0 60px;height:1px;background:linear-gradient(90deg,var(--indigo-p),transparent)}
.figure{padding-left:18px;border-left:2px solid rgba(180,156,225,.28);transition:border-color .35s}
.figure:hover{border-left-color:var(--indigo-l)}
.figure .fig-n{transition:transform .35s ease}
.figure:hover .fig-n{transform:translateX(4px)}
.figure .fig-c{border-top:none;padding-top:8px}

/* ---------- MARKETS: real cities + local vibe line ---------- */
.market{padding:40px 34px 34px}
.market .mvibe{font-family:var(--mono);font-size:12.5px;letter-spacing:1.5px;color:#B9A6E6;margin:0 0 14px;opacity:.9;font-style:normal}
.market .mdesc{margin-bottom:18px}
.market::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(83,39,157,.0) 40%,rgba(55,22,112,.28) 100%);opacity:0;transition:opacity .5s}
.market:hover::before{opacity:1}

/* ---------- PROOF: animated evidence gallery (thetechio-style reveal) ---------- */
.proof .grid{grid-template-columns:.92fr 1.08fr;align-items:start;gap:56px}
.proof .say-col{position:sticky;top:96px}
@media(max-width:860px){.proof .say-col{position:static}}
.proof .kpis{margin-top:8px}
.evstack{position:relative;display:flex;flex-direction:column;gap:26px;padding-top:6px}
.evcard{background:#F4F2F8;border-radius:16px;padding:12px;box-shadow:0 30px 64px rgba(0,0,0,.55);position:relative;
  opacity:0;transform:translateY(70px) rotate(var(--r,-1deg)) scale(.97);
  transition:opacity .8s cubic-bezier(.16,.84,.28,1),transform .9s cubic-bezier(.16,.84,.28,1);
  transition-delay:var(--dl,0s);will-change:transform,opacity}
.evcard.in{opacity:1;transform:translateY(0) rotate(var(--r0,0deg)) scale(1)}
.evcard:nth-child(1){--r:-2.4deg;--r0:-1.4deg;z-index:3}
.evcard:nth-child(2){--r:2.2deg;--r0:1deg;z-index:2;margin-left:auto;margin-right:0}
.evcard:nth-child(3){--r:-1.8deg;--r0:-.8deg;z-index:1}
.evcard img{width:100%;display:block;border-radius:10px}
.evcard .cap{position:absolute;left:-12px;top:-12px;background:var(--indigo);color:#fff;font-family:var(--mono);
  font-size:11px;letter-spacing:1.2px;text-transform:uppercase;padding:7px 13px;border-radius:10px;
  box-shadow:0 10px 24px rgba(0,0,0,.4);max-width:78%}
.evcard .cap.lift{background:var(--lift)}
.evcard .under{font-family:var(--mono);font-size:11px;letter-spacing:.8px;color:#5A5470;padding:8px 4px 2px;display:block}
.evcard.wide-card{width:100%}
.evcard.narrow-card{width:78%}
@media(max-width:520px){.evcard.narrow-card{width:100%}}

/* section marker used across refined sections */
.secmark{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p)}

@media(prefers-reduced-motion:reduce){.evcard{opacity:1;transform:none;transition:none}.count[data-to]{}}

/* ============================================================
   v8 · DEPTH PASS - sticky-stacking proof (thetechio pattern),
   real mobile navigation, and finer motion. Eyes open.
   ============================================================ */

/* ---------- NAV: hamburger on mobile, refined on desktop ---------- */
.nav .navtoggle{display:none;margin-left:auto;background:none;border:1px solid var(--crease-dark);border-radius:10px;
  width:44px;height:40px;cursor:pointer;position:relative;padding:0}
.nav .navtoggle span,.nav .navtoggle span::before,.nav .navtoggle span::after{
  content:"";position:absolute;left:11px;width:22px;height:2px;background:var(--paper);transition:.3s;border-radius:2px}
.nav .navtoggle span{top:19px}
.nav .navtoggle span::before{top:-7px}
.nav .navtoggle span::after{top:7px}
.nav.open .navtoggle span{background:transparent}
.nav.open .navtoggle span::before{transform:translateY(7px) rotate(45deg)}
.nav.open .navtoggle span::after{transform:translateY(-7px) rotate(-45deg)}
@media(max-width:820px){
  .nav{flex-wrap:wrap}
  .nav .navtoggle{display:block}
  .nav .links{margin-left:0;flex-basis:100%;flex-direction:column;flex-wrap:nowrap;gap:0;
    max-height:0;overflow:hidden;transition:max-height .4s ease;border-top:1px solid transparent}
  .nav.open .links{max-height:340px;border-top-color:var(--crease-dark);padding:6px 0 12px}
  .nav .links a{padding:13px 6px;font-size:16px;border-radius:0}
  .nav .links a.on{box-shadow:inset 3px 0 0 var(--indigo)}
}

/* ---------- PROOF v2: sticky header + stacking evidence deck ---------- */
.proof{padding:0;overflow:visible}   /* overflow:hidden on an ancestor disables sticky */
.proof .grid{display:block;max-width:none;padding:0}          /* neutralise old grid */
.proofgrid{max-width:1240px;margin:0 auto;padding:clamp(70px,10vh,120px) 32px clamp(80px,12vh,130px);
  display:grid;grid-template-columns:.82fr 1.18fr;gap:60px;align-items:start}
.proof-sticky{position:sticky;top:96px;align-self:start}
.proof-sticky .eyebrow{font-family:var(--mono);font-size:12.5px;letter-spacing:4px;text-transform:uppercase;color:var(--indigo-p);margin-bottom:18px;display:flex;align-items:center;gap:12px}
.proof-sticky .eyebrow::after{content:"";flex:0 0 46px;height:1px;background:linear-gradient(90deg,var(--indigo-p),transparent)}
.proof-sticky h2.big{font-size:clamp(34px,4.6vw,62px);line-height:1.0;letter-spacing:-1px;padding-left:0;margin:0 0 20px}
.proof-sticky h2.big::before{display:none}
.proof-sticky h2.big em{font-style:normal;color:var(--lift-dark)}
.proof-sticky .say{color:#C4BEDA;font-size:18px;max-width:42ch;margin:0 0 30px;line-height:1.7}
.proofsteps{list-style:none;margin:0;padding:0;border-top:1px solid var(--crease-dark)}
.proofsteps li{display:flex;align-items:baseline;gap:14px;padding:16px 4px;border-bottom:1px solid var(--crease-dark);
  color:var(--soft-dark);transition:color .35s,padding-left .35s;cursor:default}
.proofsteps li .ps-n{font-family:var(--mono);font-size:12.5px;letter-spacing:1px;color:var(--soft);flex:none;width:22px}
.proofsteps li .ps-t{font-family:var(--sans);font-size:16px;line-height:1.4}
.proofsteps li .ps-v{margin-left:auto;font-family:var(--display);font-weight:700;font-size:16px;color:var(--soft-dark);flex:none;transition:color .35s}
.proofsteps li.on{color:var(--paper);padding-left:12px}
.proofsteps li.on .ps-n{color:var(--indigo-p)}
.proofsteps li.on .ps-v{color:var(--lift-dark)}
.proofsteps li.on::marker{color:var(--indigo)}

/* the stacking deck */
.proof-stack{position:relative}
.pcard{position:sticky;background:#F4F2F8;border-radius:16px;padding:12px;
  box-shadow:0 -2px 0 rgba(180,156,225,.18),0 34px 70px rgba(0,0,0,.62);
  margin-bottom:44vh;transform-origin:top center}
.pcard:last-child{margin-bottom:0}
.pcard:nth-child(1){top:100px;z-index:1}
.pcard:nth-child(2){top:122px;z-index:2}
.pcard:nth-child(3){top:144px;z-index:3}
.pcard .barhead{display:flex;align-items:center;gap:8px;padding:6px 6px 12px}
.pcard .dot{width:11px;height:11px;border-radius:50%;background:#D9D3E6}
.pcard .dot.r{background:#E4897F}.pcard .dot.y{background:#E5C46A}.pcard .dot.g{background:#7FC79B}
.pcard .barhead .cap{margin-left:8px;font-family:var(--mono);font-size:11px;letter-spacing:1.2px;text-transform:uppercase;color:#6B6580}
.pcard .barhead .cap b{color:var(--indigo-d)}
.pcard .barhead .num{margin-left:auto;font-family:var(--mono);font-size:11px;color:#9A92B5}
.pcard img{width:100%;display:block;border-radius:10px}
.pcard .under{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.6px;color:#5A5470;padding:11px 6px 3px}
.pcard .under em{font-style:normal;color:var(--lift)}
@media(max-width:860px){
  .proofgrid{grid-template-columns:1fr;gap:30px}
  .proof-sticky{position:static}
  .pcard{position:static;margin-bottom:22px}
  .pcard:nth-child(n){top:auto}
}

/* ---- mobile hero override placed last so it wins over the v7 desktop ::after ---- */
@media(max-width:760px){
  .homehero.cine::after{
    background:
      linear-gradient(180deg, rgba(19,17,30,.92) 0%, rgba(19,17,30,.82) 44%, rgba(19,17,30,.74) 72%, rgba(19,17,30,.90) 100%),
      url("img/hero-crane.jpg") !important;
    background-size:cover !important;
    background-position:center, 70% 62% !important;
    background-repeat:no-repeat !important}
}

/* ============================================================
   v9 · POLISH - lamp glow on the workbench, scroll-cue placement,
   richer figure depth. Small dots, eyes open.
   ============================================================ */

/* the workbench, lit by a single warm lamp from the upper left (per the guide) */
.figures .deskwood::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(1100px 620px at 26% -12%, rgba(120,92,52,.16), transparent 58%),
    radial-gradient(900px 560px at 82% 8%, rgba(83,39,157,.14), transparent 60%)}
.figures .inner{position:relative;z-index:1}
/* a faint crane, folded into the wood, for depth */
.figures .deskwood::after{content:"";position:absolute;right:-40px;bottom:-30px;width:340px;height:266px;pointer-events:none;z-index:0;opacity:.05;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 100'%3E%3Cpolygon points='8,30 40,62 34,76' fill='%23B49CE1'/%3E%3Cpolygon points='52,6 40,62 76,62' fill='%23B49CE1'/%3E%3Cpolygon points='34,76 40,62 76,62 86,79 54,90' fill='%23B49CE1'/%3E%3Cpolygon points='76,62 86,79 106,28' fill='%23B49CE1'/%3E%3C/svg%3E") no-repeat center/contain}

/* figure hover: the accent rule and number lift together */
.figure{transition:border-color .35s}
.figure .fig-k{transition:color .35s}
.figure:hover .fig-k{color:var(--paper)}

/* scroll cue moved out of the crane, pinned to the lower-left edge */
.scrollcue{left:38px;right:auto;bottom:120px;transform:none}
@media(max-width:1100px){.scrollcue{display:none}}

/* market panel text stays legible over bright neon / sky areas */
.market .mnum,.market .mcity,.market .mtag,.market .mvibe,.market .mdesc,.market .mgo{
  text-shadow:0 2px 14px rgba(19,17,30,.72),0 1px 3px rgba(19,17,30,.6)}
.market::after{background:linear-gradient(180deg,rgba(19,17,30,.42) 0%,rgba(19,17,30,.58) 46%,rgba(19,17,30,.93) 100%)}

/* ============================================================
   V7 · THE YES PASS - 2026-07-23 (Fable)
   Appended last on purpose (F21). Anything layout-affecting is
   media-guarded. Desktop base above is untouched.
   ============================================================ */

/* --- 1 · NAV: brand it. Mono labels, crease underline, fold-active, CTA --- */
.nav{background:rgba(19,17,30,.86);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
.links a{font-family:var(--mono);font-size:12.5px;letter-spacing:2.2px;text-transform:uppercase;
  padding:12px 13px;border-radius:0;position:relative;color:#8F87A6}
.links a:hover{color:var(--paper)}
.links a.on{color:var(--paper);background:none}
.links a.on::after{content:"";position:absolute;left:13px;right:13px;bottom:6px;height:2px;
  background:linear-gradient(90deg,var(--indigo,#53279D),#B49CE1)}
.links a.on::before{content:"";position:absolute;top:0;right:0;width:14px;height:14px;
  background:linear-gradient(135deg,transparent 0 50%,#53279D 50.5%);opacity:.9}
.nav .navcta{font-family:var(--mono);font-size:12.5px;letter-spacing:2px;text-transform:uppercase;
  color:var(--paper);border:1px solid #53279D;padding:9px 16px;margin-left:18px;border-radius:10px;
  text-decoration:none;transition:background .2s,transform .2s;white-space:nowrap}
.nav .navcta:hover{background:#53279D;transform:translateY(-1px)}
@media(max-width:900px){.nav .navcta{display:none}}

/* --- 2 · STATEMENT: one viewport, integrated graphic, no dead air --- */
.statement{padding:clamp(64px,10vh,120px) 0}
.statement .wide{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr);
  gap:40px;align-items:center;position:relative}
.statement .smark,.statement .big,.statement .foot-note{grid-column:1}
.statement .big{font-size:clamp(34px,4.6vw,62px);line-height:1.12;margin:14px 0 22px}
.statement .foot-note{margin-top:0}
.creasegraphic{position:relative;right:auto;top:auto;transform:none;grid-column:2;grid-row:1/span 3;
  width:100%;max-width:440px;justify-self:end;opacity:.5}
@media(max-width:900px){
  .statement .wide{grid-template-columns:1fr}
  .creasegraphic{grid-column:1;grid-row:auto;max-width:300px;justify-self:center;opacity:.3;margin-top:10px}
}

/* --- 3 · FIGURES: paper sheets back on the desk (the guide's biggest win) --- */
.deskwood{background:linear-gradient(rgba(19,17,30,.42),rgba(19,17,30,.58)),url("img/workbench.jpg") center/cover;
  box-shadow:inset 0 0 140px rgba(0,0,0,.72)}
.figure{background:rgba(240,237,245,.045);border:1px solid rgba(180,156,225,.22);border-radius:10px;
  padding:24px 22px 20px;position:relative;
  clip-path:polygon(0 0,calc(100% - 22px) 0,100% 22px,100% 100%,0 100%);
  box-shadow:0 18px 40px rgba(0,0,0,.45);transition:transform .45s ease,background .3s}
.figure::before{content:"";position:absolute;top:0;right:0;width:22px;height:22px;
  background:linear-gradient(225deg,rgba(180,156,225,.5) 0 50%,transparent 50.5%)}
.figure:hover{transform:translateY(-4px) rotate(0deg)!important;background:rgba(240,237,245,.07)}
@media(min-width:901px){
  .figgrid{gap:26px 24px}
  .figure:nth-child(odd){transform:rotate(-.55deg)}
  .figure:nth-child(even){transform:rotate(.4deg)}
}
.fig-c{border-top:1px dashed rgba(180,156,225,.28)}

/* --- 4 · METHOD TEASER: the pattern strip. Abstract, not tutorial --- */
.foldrow{position:relative;isolation:isolate}
.foldrow::before{content:"";position:absolute;left:2%;right:2%;top:50%;z-index:-1;
  border-top:1.5px dashed rgba(180,156,225,.3)}
.foldcard{background:linear-gradient(150deg,rgba(83,39,157,var(--fd,.10)),rgba(19,17,30,.9) 62%);
  clip-path:polygon(0 0,calc(100% - var(--ear,26px)) 0,100% var(--ear,26px),100% 100%,0 100%);
  border:1px solid rgba(180,156,225,.24)}
.foldcard::before{content:"";position:absolute;top:0;right:0;width:var(--ear,26px);height:var(--ear,26px);
  background:linear-gradient(225deg,#B49CE1 0 50%,transparent 50.5%);opacity:.65}
.foldcard:nth-child(1){--fd:.08;--ear:20px}
.foldcard:nth-child(2){--fd:.16;--ear:30px}
.foldcard:nth-child(3){--fd:.26;--ear:40px}
.foldcard:nth-child(4){--fd:.40;--ear:52px}
.foldcard:nth-child(4) .ft{color:#B49CE1}
.foldcard:hover{transform:translateY(-5px);border-color:rgba(180,156,225,.5)}
.foldcard .fn{font-family:var(--mono);letter-spacing:2px}

/* --- 5 · PROOF: tighter cadence, honest property note --- */
.pcard{margin-bottom:36vh}
.proofgrid{padding-bottom:clamp(56px,8vh,90px)}

/* --- 6 · VOICE FIX: poetic lines out of the code font --- */
.mvibe{font-family:var(--body,inherit);font-style:italic;letter-spacing:0;text-transform:none;
  font-size:14.5px;color:rgba(240,237,245,.72)}

/* --- 7 · GLOBAL RHYTHM --- */
.methodtease{padding:clamp(64px,9vh,104px) 0}
.refused{padding-top:clamp(56px,8vh,96px)}
.finalcta{padding:clamp(80px,12vh,130px) 0}

/* --- 8 · MOBILE PACING (no sticky choreography under 820px, so no scroll-gap between cards) --- */
@media(max-width:820px){
  .pcard{margin-bottom:48px}
  .proof-stack .pcard:last-child{margin-bottom:0}
}

/* ============================================================
   v10 · INTERIOR ELEVATION - 2026-07-29 (Opus 5)
   The homepage reached v7 on 7/24. The ten interior pages were
   still wearing the 7/21 shell: flat corner triangle, no
   atmosphere, crease markers that vanished under 1020px, and
   workbench sheets with none of the paper materiality the guide
   calls the biggest visual win. This layer carries the v7
   vocabulary inward. Appended last (F21); layout rules are
   media-guarded so the desktop base above is untouched.
   ============================================================ */

/* --- 1 · THE CORNER FOLD: a lit crease, not a colour block --- */
.hero:not(.homehero) .fold{
  width:clamp(150px,21vw,290px);height:clamp(150px,21vw,290px);opacity:1;
  background:
    linear-gradient(135deg,rgba(124,82,199,.30) 0 50%,transparent 50.5%),
    linear-gradient(160deg,rgba(55,22,112,.88) 0 50%,transparent 50.5%);
  filter:drop-shadow(-6px 8px 22px rgba(0,0,0,.45))}
/* the lit crease where the corner turns over */
.hero:not(.homehero) .fold::after{content:"";position:absolute;inset:0;
  background:
    linear-gradient(160deg,transparent calc(50% - 1px),rgba(180,156,225,.55) 50%,transparent calc(50% + 1px)),
    linear-gradient(135deg,transparent calc(50% - .6px),rgba(180,156,225,.22) 50%,transparent calc(50% + .6px))}
@media(max-width:720px){.hero:not(.homehero) .fold{width:132px;height:132px;opacity:.8}}

/* --- 2 · ATMOSPHERE PER SHEET: every interior page has its own air --- */
.hero.pattern::after,.hero.bench::after,.hero.hands::after,.hero.casehero::after{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none}
.hero.pattern .wrap,.hero.bench .wrap,.hero.hands .wrap,.hero.casehero .wrap{position:relative;z-index:2}
.hero.pattern::after{background:linear-gradient(rgba(19,17,30,.90),rgba(19,17,30,.93)),
  url("img/paper-fiber.jpg") center/cover}
.hero.bench::after{background:linear-gradient(100deg,rgba(19,17,30,.94) 22%,rgba(19,17,30,.72) 100%),
  url("img/workbench.jpg") center/cover}
.hero.hands::after{background:linear-gradient(96deg,rgba(19,17,30,.95) 30%,rgba(19,17,30,.55) 100%),
  url("img/hands-folding.jpg") right center/cover}
.hero.casehero::after{background:linear-gradient(rgba(19,17,30,.88),rgba(19,17,30,.94)),
  url("img/crumple-indigo.jpg") center/cover}

/* --- 3 · INTERIOR HEADLINE: give the first line real weight --- */
.hero:not(.homehero) h1{font-size:clamp(34px,4.6vw,62px);line-height:1.06;letter-spacing:-.4px;
  max-width:19ch;margin:0}
.hero:not(.homehero) .sub{max-width:62ch;margin-top:20px}
.hero:not(.homehero) .kicker{margin-bottom:16px}

/* --- 4 · THE FOLIO: this sheet's place in the set --- */
.folio{display:flex;align-items:center;gap:13px;margin-top:30px;
  font-family:var(--mono);font-size:11px;letter-spacing:2.6px;text-transform:uppercase;
  color:rgba(180,156,225,.74)}
.folio .fnum{color:var(--paper);border:1px solid rgba(180,156,225,.42);
  padding:5px 10px;border-radius:6px;background:rgba(83,39,157,.22);white-space:nowrap}
.folio .frule{flex:0 0 42px;height:0;border-top:1.5px dashed rgba(180,156,225,.4)}
@media(max-width:720px){
  .folio{gap:9px;font-size:11px;letter-spacing:1.8px;flex-wrap:wrap}
  .folio .frule{flex-basis:24px}}

/* --- 5 · THE CREASE SPINE: the fold markers become the page's edge --- */
@media(min-width:1021px){
  .foldstep::before{left:-92px;top:2px;padding:5px 10px;border-radius:6px;
    background:rgba(83,39,157,.16);border:1px solid rgba(83,39,157,.34);
    color:var(--indigo-p,#7C52C7);font-size:11px;letter-spacing:2px;line-height:1.1}
  .foldstep::after{content:"";position:absolute;left:-58px;top:38px;bottom:6px;
    border-left:1.5px dashed rgba(83,39,157,.3)}
  .section.paper .foldstep::before,.section.paper2 .foldstep::before{
    background:rgba(83,39,157,.10);border-color:rgba(83,39,157,.3)}
}
/* the marker used to disappear entirely under 1020px - now it leads the block */
@media(max-width:1020px){
  .foldstep::before{display:inline-block;position:static;margin:0 0 12px;
    padding:5px 10px;border-radius:6px;background:rgba(83,39,157,.14);
    border:1px solid rgba(83,39,157,.32);color:var(--indigo-p,#7C52C7);
    font-family:var(--mono);font-size:11px;letter-spacing:2px}
}
/* the five folds deepen as the sheet is worked, 01 lightest to 05 darkest */
.foldstep[data-fold="FOLD 02"]::before{background:rgba(83,39,157,.22)}
.foldstep[data-fold="FOLD 03"]::before{background:rgba(83,39,157,.30)}
.foldstep[data-fold="FOLD 04"]::before{background:rgba(83,39,157,.38);color:#B49CE1}
.foldstep[data-fold="FOLD 05"]::before{background:rgba(83,39,157,.48);color:#B49CE1;
  border-color:rgba(180,156,225,.5)}

/* --- 6 · WORKBENCH SHEETS: paper on a desk, dog-eared and lifted --- */
.bench .sheet{
  clip-path:polygon(0 0,calc(100% - 30px) 0,100% 30px,100% 100%,0 100%);
  box-shadow:0 16px 34px rgba(19,17,30,.20),0 2px 5px rgba(19,17,30,.12);
  transition:transform .45s cubic-bezier(.2,.7,.3,1),box-shadow .45s}
.bench .sheet:hover{transform:translateY(-5px) rotate(0deg)!important;
  box-shadow:0 26px 52px rgba(19,17,30,.28)}
@media(min-width:901px){
  .bench .sheet:nth-child(odd){transform:rotate(-.5deg)}
  .bench .sheet:nth-child(even){transform:rotate(.42deg)}}

/* --- 7 · THE UNFOLD DIAGRAM: give the stages room and a lit joint --- */
.unfold{margin:44px 0 10px}
.stage svg{transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.stage:hover svg{transform:translateY(-6px)}
.joint{border-top-color:rgba(180,156,225,.42)}

/* --- 8 · INTERIOR RHYTHM: stop sections running into each other --- */
main.creased>.section{padding-top:clamp(52px,7vh,86px);padding-bottom:clamp(52px,7vh,86px)}
.selfref{border-radius:0 12px 12px 0}

/* --- 9 · INTERIOR HERO HEIGHT: one rule instead of ten inline paddings --- */
.hero:not(.homehero){padding:clamp(74px,11vh,124px) 0 clamp(56px,8vh,84px)}

/* --- 10 · WORKBENCH SHEET TYPOGRAPHY: the markup already encodes intent
       (.big.indigo = authority, .big.lift = the win, .big.mono = a step
       number) but only .sheet .big was ever defined, so 33 sheets across
       7 pages rendered flat and leaned on inline font sizes. Meet the
       markup where it is. --- */
.sheet .big.lift{color:var(--lift)}
.sheet .big.indigo{color:var(--indigo)}
.sheet .big.mono{font-family:var(--mono);font-size:24px;letter-spacing:1.5px;
  color:var(--indigo);font-weight:700}
.sheet h3{margin:9px 0 0;font-size:18px;line-height:1.26;color:var(--ink)}
.sheet .cap{font-size:14.5px;color:#4A445E;margin-top:8px;line-height:1.58}
.sheet .n.lift{color:var(--lift)}

/* ============================================================
   v11 · THE FOLD ENGINE - 2026-07-29 (Opus 5)
   Custom graphics instead of a stock library. Every visual on the
   interior pages is folded paper geometry generated in the browser:
   a unique crease pattern per sheet, bespoke fold glyphs, creased
   section edges, and a menu that IS a crease pattern. Weightless,
   infinitely variable, and not purchasable by a competitor.
   Draw motion uses native scroll-driven animation where supported
   and falls back to IntersectionObserver. Appended last (F21).
   ============================================================ */

/* --- 1 · THE CREASE FIELD --- */
.cfield{width:100%;height:100%;display:block;overflow:visible}
.cfield line,.cfield rect,.cfield polygon{
  fill:none;vector-effect:non-scaling-stroke;
  stroke-dasharray:var(--len);stroke-dashoffset:var(--len)}
.cfield .cf-m line,.cfield .cf-m rect{stroke:rgba(180,156,225,.42);stroke-width:1}
.cfield .cf-v line,.cfield .cf-v polygon{stroke:rgba(124,82,199,.40);stroke-width:1;stroke-dasharray:6 7}

/* on paper sections the notation inverts to ink on white */
.section.paper .cfield .cf-m line,.section.paper .cfield .cf-m rect,
.section.paper2 .cfield .cf-m line,.section.paper2 .cfield .cf-m rect{stroke:rgba(83,39,157,.30)}
.section.paper .cfield .cf-v line,.section.paper .cfield .cf-v polygon,
.section.paper2 .cfield .cf-v line,.section.paper2 .cfield .cf-v polygon{stroke:rgba(83,39,157,.24)}

@keyframes creasedraw{to{stroke-dashoffset:0}}
.cfield.drawn line,.cfield.drawn rect,.cfield.drawn polygon{
  animation:creasedraw .95s cubic-bezier(.25,.8,.3,1) forwards;animation-delay:var(--dly,0s)}
.cf-static .cfield line,.cf-static .cfield rect,.cf-static .cfield polygon{stroke-dashoffset:0}
@supports (animation-timeline:view()){
  .cf-native .cfield line,.cf-native .cfield rect,.cf-native .cfield polygon{
    animation:creasedraw linear both;
    animation-timeline:view();animation-range:entry 5% cover 40%}
}

.cfield-wrap{position:absolute;pointer-events:none;z-index:1}
.cfw-hero{top:50%;right:-4%;transform:translateY(-50%);width:min(46vw,520px);aspect-ratio:1;opacity:.5}
.cfw-tail{left:50%;bottom:-6%;transform:translateX(-50%);width:min(72vw,760px);aspect-ratio:1;opacity:.22}
main .section{position:relative;overflow:hidden}
main .section>.wrap{position:relative;z-index:2}
.hero .cfield-wrap{z-index:1}
@media(max-width:900px){
  .cfw-hero{right:-18%;width:74vw;opacity:.3}
  .cfw-tail{width:110vw;opacity:.16}
}

/* --- 2 · FOLD GLYPHS: two planes of paper, one lit, one in shadow --- */
.fi{width:32px;height:32px;display:block;flex:0 0 auto;overflow:visible}
.fi .fi-o{fill:none;stroke:rgba(180,156,225,.62);stroke-width:1.5;stroke-linejoin:round}
.fi .fi-l{fill:rgba(124,82,199,.55);stroke:none}
.fi .fi-s{fill:rgba(55,22,112,.85);stroke:none}
.fi .fi-c{fill:none;stroke:rgba(180,156,225,.85);stroke-width:1.5;stroke-linecap:round}
.fi .fi-d{fill:none;stroke:rgba(180,156,225,.5);stroke-width:1.3;stroke-dasharray:4 4;stroke-linecap:round}
.fi .fi-x{fill:none;stroke:rgba(154,146,181,.45);stroke-width:1.4;stroke-dasharray:5 5}
.section.paper .fi .fi-o,.section.paper2 .fi .fi-o{stroke:rgba(83,39,157,.55)}
.section.paper .fi .fi-l,.section.paper2 .fi .fi-l{fill:rgba(124,82,199,.5)}
.section.paper .fi .fi-s,.section.paper2 .fi .fi-s{fill:rgba(55,22,112,.72)}
.section.paper .fi .fi-c,.section.paper2 .fi .fi-c{stroke:rgba(83,39,157,.8)}
.section.paper .fi .fi-d,.section.paper2 .fi .fi-d{stroke:rgba(83,39,157,.45)}
.fi-head{width:26px;height:26px;display:inline-block;vertical-align:-3px;margin-right:11px}
h2 .fi-head{transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.foldstep:hover h2 .fi-head{transform:translateY(-3px) rotate(-4deg)}

/* --- 3 · THE CREASED EDGE between sections --- */
.fdiv-host{position:relative;height:34px;margin-bottom:-34px;pointer-events:none;z-index:3}
.fdiv{width:100%;height:34px;display:block}
.fd-line{fill:none;stroke:rgba(180,156,225,.30);stroke-width:1.2;
  stroke-dasharray:3000;stroke-dashoffset:3000}
.fdiv.drawn .fd-line{animation:creasedraw 1.1s cubic-bezier(.25,.8,.3,1) forwards}
.cf-static .fd-line{stroke-dashoffset:0}
@supports (animation-timeline:view()){
  .cf-native .fd-line{animation:creasedraw linear both;
    animation-timeline:view();animation-range:entry 0% entry 85%}
}

/* --- 4 · THE CREASE NAVIGATOR: the menu is the fold map --- */
.creasenav{position:fixed;inset:0;z-index:900;display:none;
  background:radial-gradient(120% 120% at 78% 8%,rgba(55,22,112,.55),rgba(19,17,30,.97) 58%);
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}
.creasenav.show{display:block;animation:cnin .34s ease both}
@keyframes cnin{from{opacity:0}to{opacity:1}}
.cn-inner{position:absolute;inset:0;display:grid;
  grid-template-columns:1fr minmax(300px,44%);align-items:center;
  padding:clamp(74px,12vh,120px) clamp(22px,6vw,90px) 40px}
.cn-art{position:relative;width:min(46vw,520px);aspect-ratio:1;opacity:.55;justify-self:start}
.cn-list{display:flex;flex-direction:column;gap:2px;justify-self:stretch}
.cn-item{display:flex;align-items:center;gap:16px;text-decoration:none;
  padding:15px 16px;border-radius:10px;position:relative;
  border:1px solid transparent;transform-origin:top center;
  animation:cnfold .5s cubic-bezier(.2,.75,.3,1) both;animation-delay:calc(var(--i) * .06s + .06s)}
@keyframes cnfold{from{opacity:0;transform:perspective(700px) rotateX(-28deg) translateY(-10px)}
  to{opacity:1;transform:none}}
.cn-n{font-family:var(--mono);font-size:12.5px;letter-spacing:2.4px;color:rgba(180,156,225,.62);width:26px}
.cn-t{font-family:var(--display);font-weight:700;font-size:clamp(26px,4.3vw,50px);
  line-height:1.05;color:var(--paper);letter-spacing:-.4px;flex:1}
.cn-item .fi{width:26px;height:26px;opacity:.5;transition:opacity .3s,transform .45s}
.cn-item:hover{border-color:rgba(180,156,225,.28);background:rgba(83,39,157,.16)}
.cn-item:hover .cn-t{color:#fff}
.cn-item:hover .fi{opacity:1;transform:translateX(3px) rotate(-5deg)}
.cn-item.on .cn-t{color:#B49CE1}
.cn-item.on::before{content:"";position:absolute;left:0;top:12px;bottom:12px;width:2px;
  background:linear-gradient(180deg,#53279D,#B49CE1)}
.cn-foot{position:absolute;left:clamp(22px,6vw,90px);bottom:26px;display:flex;gap:14px;
  font-family:var(--mono);font-size:11px;letter-spacing:2.4px;text-transform:uppercase;
  color:rgba(180,156,225,.5)}
@media(max-width:900px){
  .cn-inner{grid-template-columns:1fr;align-content:start;gap:20px;padding-top:96px}
  .cn-art{position:absolute;right:-24%;top:8%;width:86vw;opacity:.22;justify-self:end}
  .cn-list{position:relative;z-index:2}
  .cn-item{padding:12px}
}
@media(prefers-reduced-motion:reduce){
  .cn-item{animation:none;opacity:1;transform:none}
  .creasenav.show{animation:none}
}
/* the old sheet-collapse menu is superseded by the navigator */
@media(max-width:820px){.nav.open .links{max-height:0;border-top-color:transparent;padding:0}}

/* --- 5 · THE SCROLL IS THE FOLDING SEQUENCE ---
   Each section hinges in on its top crease. Native timeline only, so
   there is no scroll handler cost, and it is off under reduced motion. */
@supports (animation-timeline:view()){
  .cf-native main>.section{animation:sectionfold linear both;
    animation-timeline:view();animation-range:entry 0% entry 62%;
    transform-origin:top center;will-change:transform,opacity}
  @keyframes sectionfold{
    from{opacity:.25;transform:perspective(1400px) rotateX(-5.5deg) translateY(16px)}
    to{opacity:1;transform:none}}
}

/* --- 6 · ONE MARK PER HEADING ---
   The generic rotated-square bullet was the same on every h2. Where a
   fold glyph is injected it takes that exact slot, so the heading keeps
   its alignment but the mark now carries meaning: silo, engine, footing,
   town, report. --- */
h2.has-glyph{padding-left:42px}
h2.has-glyph::before{display:none}
h2.has-glyph .fi-head{position:absolute;left:0;top:3px;width:30px;height:30px;
  margin:0;display:block;vertical-align:baseline}
@media(max-width:1020px){
  h2.has-glyph{padding-left:38px}
  h2.has-glyph .fi-head{width:26px;height:26px;top:2px}
}

/* --- 7 · SECTION FOLD, TUNED ---
   The first pass dropped incoming sections to .25 opacity, which read as a
   dead grey slab at first paint. Paper in shadow is still paper. --- */
@supports (animation-timeline:view()){
  @keyframes sectionfold{
    from{opacity:.55;transform:perspective(1600px) rotateX(-4deg) translateY(12px)}
    to{opacity:1;transform:none}}
  .cf-native main>.section{animation-range:entry 0% entry 48%}
  /* the first section after the hero is already on screen at load; it should
     not animate in from nothing */
  .cf-native main>.section:first-child{animation:none;opacity:1;transform:none}
}

/* --- 8 · THE SHEET INDEX ---
   The navigator carries all eleven sheets, so it is a real index and not a
   second copy of the top bar. The five case studies sit under the six main
   sheets the way spokes sit under a hub. --- */
.cn-inner{grid-template-columns:minmax(0,.82fr) minmax(320px,1fr);gap:clamp(24px,5vw,70px)}
.cn-col{display:flex;flex-direction:column;gap:22px;justify-self:stretch;min-width:0}
.cn-art{width:100%;max-width:520px;position:relative}
.cn-artcap{position:absolute;left:0;bottom:-42px;display:flex;flex-direction:column;gap:3px}
.cn-artcap b{font-family:var(--mono);font-size:11px;letter-spacing:2.6px;text-transform:uppercase;
  color:rgba(180,156,225,.8);font-weight:400}
.cn-artcap span{font-family:var(--mono);font-size:11px;letter-spacing:2px;text-transform:uppercase;
  color:rgba(180,156,225,.42)}

.cn-cases{border-top:1.5px dashed rgba(180,156,225,.24);padding-top:18px}
.cn-caplabel{font-family:var(--mono);font-size:11px;letter-spacing:2.6px;text-transform:uppercase;
  color:rgba(180,156,225,.5);margin-bottom:12px}
.cn-casegrid{display:grid;grid-template-columns:1fr 1fr;gap:6px 20px}
.cn-case{display:flex;align-items:baseline;gap:11px;text-decoration:none;padding:7px 9px;
  border-radius:6px;color:rgba(240,237,245,.72);font-size:14.5px;line-height:1.3;
  border:1px solid transparent;transform-origin:top center;
  animation:cnfold .5s cubic-bezier(.2,.75,.3,1) both;animation-delay:calc(var(--i) * .05s + .1s)}
.cn-case .cn-n{width:22px;font-size:11px}
.cn-case:hover{background:rgba(83,39,157,.18);border-color:rgba(180,156,225,.22);color:#fff}
.cn-case.on{color:#B49CE1}
@media(max-width:900px){
  .cn-casegrid{grid-template-columns:1fr}
  .cn-artcap{display:none}
  .cn-inner{grid-template-columns:1fr}
}
@media(prefers-reduced-motion:reduce){.cn-case{animation:none;opacity:1;transform:none}}

/* --- 9 · THE INDEX TRIGGER: a quiet way into the map on desktop --- */
.nav .navindex{display:inline-flex;align-items:center;gap:9px;margin-left:auto;
  background:none;border:1px solid rgba(180,156,225,.26);border-radius:10px;
  padding:8px 14px;cursor:pointer;color:rgba(240,237,245,.82);
  font-family:var(--mono);font-size:11px;letter-spacing:2.2px;text-transform:uppercase;
  transition:border-color .25s,background .25s,transform .25s}
.nav .navindex .fi{width:17px;height:17px;opacity:.8}
.nav .navindex:hover{border-color:rgba(180,156,225,.6);background:rgba(83,39,157,.2);
  transform:translateY(-1px)}
.nav .navcta{margin-left:14px}
@media(max-width:820px){.nav .navindex{display:none}}
@media(max-width:1120px) and (min-width:821px){.nav .navindex span{display:none}
  .nav .navindex{padding:8px 10px}}

/* --- 10 · NAVIGATOR FIT ---
   Eleven sheets plus a label has to survive a 640px-tall laptop window.
   Align to the top, let the panel scroll rather than clip, and stop the
   art caption from landing on the footer. --- */
.cn-inner{align-items:center;align-content:center;overflow-y:auto;overscroll-behavior:contain;
  padding:clamp(66px,9vh,104px) clamp(22px,6vw,90px) 64px}
.cn-art{align-self:center;display:flex;flex-direction:column;gap:14px}
.cn-artcap{position:static;left:auto;bottom:auto}
.cn-item{padding:10px 14px}
.cn-t{font-size:clamp(24px,3.5vw,43px)}
.cn-col{gap:16px}
.cn-cases{padding-top:14px}
.cn-foot{background:linear-gradient(180deg,transparent,rgba(19,17,30,.9) 40%);
  padding:14px clamp(22px,6vw,90px) 18px;left:0;right:0;bottom:0;justify-content:flex-start}
@media(max-height:760px){
  .cn-art{display:none}                    /* the map yields to the index on short screens */
  .cn-inner{grid-template-columns:1fr;max-width:820px;margin:0 auto}
  .cn-t{font-size:clamp(21px,2.7vw,32px)}
  .cn-item{padding:8px 12px}
}

/* --- 11 · CASE HERO META: the kinetic headline has descenders; give the
       vertical/market/role strip room to breathe under it --- */
.hero .meta{margin-top:22px;margin-bottom:0;gap:30px}
.hero .meta+.folio{margin-top:26px}

/* ============================================================
   v12 · RHYTHM AND PHOTOGRAPHY - 2026-07-29 (Opus 5)
   The interiors were one section shape repeated: wrap, heading,
   paragraphs, forever. This layer gives the pages a pulse: full
   bleed photographic breakers with real parallax, pull quotes that
   stop the reading, asymmetric image splits, a horizontally
   scrolled market strip, and stat bands on slate. Long section,
   short section, image, quote, back to reading.
   The photography is the brand's own subject matter, graded through
   tone.py into one nocturnal system. Not borrowed authority: paper,
   hands, benches, and the three real markets.
   ============================================================ */

/* --- KILL THE SECTION HINGE ---
   v11 folded every <section> on its top edge. Backgrounds rotated with
   them, so adjacent sections showed a seam and the whole page read as
   broken. Motion belongs to the CONTENT and the IMAGES, never to the
   surface a section is painted on. --- */
@supports (animation-timeline:view()){
  .cf-native main>.section{animation:none;opacity:1;transform:none;will-change:auto}
}

/* --- 1 · THE BREAKER: full bleed photograph, parallax, one line of type --- */
.breaker{position:relative;overflow:hidden;isolation:isolate;
  min-height:clamp(360px,62vh,620px);display:flex;align-items:flex-end;
  padding:0 0 clamp(30px,5vh,58px)}
.bk-img{position:absolute;left:0;right:0;top:-14%;bottom:-14%;z-index:0;
  background-size:cover;background-position:center;will-change:transform}
.breaker::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(19,17,30,.30) 0%,rgba(19,17,30,.18) 42%,rgba(19,17,30,.88) 100%)}
.bk-copy{position:relative;z-index:2;width:min(1180px,92vw);margin:0 auto}
.bk-kicker{font-family:var(--mono);font-size:11px;letter-spacing:2.8px;text-transform:uppercase;
  color:rgba(180,156,225,.9);margin-bottom:12px;display:block}
.bk-line{font-family:var(--display);font-weight:700;color:var(--paper);
  font-size:clamp(26px,4.3vw,50px);line-height:1.08;letter-spacing:-.5px;
  max-width:20ch;margin:0;text-shadow:0 3px 26px rgba(19,17,30,.75)}
.bk-line em{font-style:normal;color:#B49CE1}
/* a light breaker, for the crane on white */
.breaker.light::after{background:linear-gradient(180deg,rgba(240,237,245,.10) 0%,
  rgba(240,237,245,.30) 55%,rgba(240,237,245,.92) 100%)}
.breaker.light .bk-line{color:var(--ink);text-shadow:none}
.breaker.light .bk-kicker{color:var(--indigo)}
.breaker.light .bk-line em{color:var(--indigo)}
/* a tall cinematic variant for the one moment per page that earns it */
.breaker.tall{min-height:clamp(460px,86vh,860px)}

@supports (animation-timeline:view()){
  .cf-native .bk-img{animation:bkpar linear both;
    animation-timeline:view();animation-range:cover 0% cover 100%}
  @keyframes bkpar{from{transform:translateY(-6.5%) scale(1.04)}
    to{transform:translateY(6.5%) scale(1.04)}}
  .cf-native .bk-copy{animation:bkcopy linear both;
    animation-timeline:view();animation-range:entry 12% entry 78%}
  @keyframes bkcopy{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
}
@media(prefers-reduced-motion:reduce){
  .cf-native .bk-img,.cf-native .bk-copy{animation:none;transform:none;opacity:1}
}

/* --- 2 · THE PULL QUOTE: a short stop between long reads --- */
.pullquote{position:relative;padding:clamp(52px,8vh,96px) 0;overflow:hidden}
.pullquote .wrap{position:relative;z-index:2}
.pq{font-family:var(--display);font-weight:700;letter-spacing:-.4px;
  font-size:clamp(24px,3.5vw,43px);line-height:1.18;margin:0;max-width:24ch;
  position:relative;padding-left:clamp(20px,3vw,44px)}
.pq::before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;
  background:linear-gradient(180deg,#53279D,#B49CE1)}
.pq em{font-style:normal;color:#B49CE1}
.pq-by{display:block;margin-top:18px;font-family:var(--mono);font-size:11px;
  letter-spacing:2.6px;text-transform:uppercase;color:rgba(180,156,225,.62);padding-left:clamp(20px,3vw,44px)}
.section.paper .pq em,.section.paper2 .pq em{color:var(--indigo)}
.section.paper .pq-by,.section.paper2 .pq-by{color:var(--soft)}

/* --- 3 · THE SPLIT: asymmetric photograph beside the argument --- */
.split{padding:clamp(56px,8vh,100px) 0;position:relative;overflow:hidden}
.split .wrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.86fr);
  gap:clamp(26px,4vw,66px);align-items:center}
.split.flip .wrap{grid-template-columns:minmax(0,.86fr) minmax(0,1fr)}
.split.flip .sp-media{order:-1}
.sp-media{position:relative;aspect-ratio:4/5;overflow:hidden;border-radius:2px;
  clip-path:polygon(0 0,calc(100% - 34px) 0,100% 34px,100% 100%,0 100%)}
.sp-media .bk-img{top:-8%;bottom:-8%}
.sp-media::after{content:"";position:absolute;top:0;right:0;width:34px;height:34px;z-index:2;
  background:linear-gradient(225deg,rgba(180,156,225,.55) 0 50%,transparent 50.5%)}
.sp-cap{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:16px 18px;
  font-family:var(--mono);font-size:11px;letter-spacing:2.2px;text-transform:uppercase;
  color:rgba(240,237,245,.85);background:linear-gradient(transparent,rgba(19,17,30,.8))}
@media(max-width:860px){
  .split .wrap,.split.flip .wrap{grid-template-columns:1fr}
  .split.flip .sp-media{order:0}
  .sp-media{aspect-ratio:16/10}
}

/* --- 4 · THE MARKET STRIP: the one place the page scrolls sideways --- */
.strip{padding:clamp(48px,7vh,86px) 0;overflow:hidden}
.strip-head{width:min(1180px,92vw);margin:0 auto clamp(20px,3vh,34px)}
.strip-rail{display:flex;gap:18px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding:6px clamp(22px,4vw,60px) 22px;scrollbar-width:thin;
  scrollbar-color:rgba(180,156,225,.4) transparent}
.strip-rail::-webkit-scrollbar{height:6px}
.strip-rail::-webkit-scrollbar-thumb{background:rgba(180,156,225,.35);border-radius:6px}
.strip-card{flex:0 0 clamp(240px,32vw,380px);scroll-snap-align:center;position:relative;
  aspect-ratio:3/4;overflow:hidden;text-decoration:none;
  clip-path:polygon(0 0,calc(100% - 26px) 0,100% 26px,100% 100%,0 100%);
  transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.strip-card:hover{transform:translateY(-6px)}
.strip-card .bk-img{top:-6%;bottom:-6%}
.strip-card::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(19,17,30,.15),rgba(19,17,30,.86))}
.sc-body{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:20px}
.sc-city{font-family:var(--display);font-weight:700;font-size:clamp(21px,2.7vw,32px);
  color:var(--paper);line-height:1.1;margin:0 0 6px}
.sc-meta{font-family:var(--mono);font-size:11px;letter-spacing:2.2px;text-transform:uppercase;
  color:rgba(180,156,225,.85)}

/* --- 5 · THE STAT BAND: numbers cut into slate --- */
.statband{position:relative;overflow:hidden;padding:clamp(48px,7vh,84px) 0}
.statband .bk-img{top:0;bottom:0}
.statband::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(90deg,rgba(19,17,30,.92),rgba(19,17,30,.72))}
.statband .wrap{position:relative;z-index:2;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:clamp(20px,3vw,44px)}
.sb{border-left:1.5px dashed rgba(180,156,225,.3);padding-left:18px}
.sb-n{font-family:var(--display);font-weight:700;font-size:clamp(34px,4.6vw,62px);
  line-height:1;color:var(--paper);display:block}
.sb-n.lift{color:#5FD3A0}
.sb-n.pale{color:#B49CE1}
.sb-c{display:block;margin-top:9px;font-size:14.5px;line-height:1.5;color:rgba(240,237,245,.72);max-width:26ch}

/* --- 12 · IMAGES ARE REAL <img> NOW (visual guide s10: every image gets
       genuine alt text; brief s12: Core Web Vitals). Same box, same parallax,
       but crawlable, described, lazy, and dimensioned so nothing shifts. --- */
img.bk-img{object-fit:cover;width:100%;height:auto;min-height:100%;max-width:none;
  display:block;border:0}
.sp-media img.bk-img,.strip-card img.bk-img,.statband img.bk-img{height:100%}

/* ============================================================
   v13 · THE EVIDENCE FRAME - 2026-07-29 (Opus 5)
   Built to the Visual Guide section 6 spec, which was written and
   then never implemented. Case studies were making claims with no
   visible proof. This is the branded screenshot frame: real data,
   presented in the brand's language, laid on the desk like printed
   evidence. Ink card, crease border, indigo fold corner, mono
   source caption, resting at a slight angle and straightening
   when you look closer.
   ============================================================ */
.evidence{
  background:var(--ink2,#1E1A2E);
  border:1px solid var(--crease-dark,rgba(180,156,225,.28));
  border-radius:16px;
  padding:16px;
  position:relative;
  overflow:hidden;
  transform:rotate(-0.8deg);
  transition:transform .35s cubic-bezier(.2,.7,.3,1),box-shadow .35s;
  box-shadow:0 18px 44px rgba(0,0,0,.42);
  max-width:560px;
  margin:26px 0}
.evidence::after{
  content:"";position:absolute;top:0;right:0;width:54px;height:54px;z-index:2;
  background:linear-gradient(135deg,var(--indigo,#53279D) 0 50%,transparent 50.5%);
  opacity:.85}
.evidence img{width:100%;border-radius:10px;display:block;height:auto}
.evidence .source{
  font-family:var(--mono);font-size:12.5px;letter-spacing:1.5px;
  color:var(--soft-dark,rgba(180,156,225,.66));text-transform:uppercase;
  margin-top:12px;display:block;line-height:1.5}
.evidence:hover{transform:rotate(0deg);box-shadow:0 26px 60px rgba(0,0,0,.5)}
/* on a paper section the frame stays ink, so the screenshot still reads as
   something laid ON the page rather than printed into it */
.section.paper .evidence,.section.paper2 .evidence{
  box-shadow:0 18px 40px rgba(19,17,30,.28)}
@media(max-width:720px){
  .evidence{transform:none;margin:22px 0}
  .evidence:hover{transform:none}
}
/* the guide is explicit: images are UNCOVERED, not moved. No slide, no scale,
   no bounce on entrance. Text unfolds; paper is simply revealed. */
@supports (animation-timeline:view()){
  .cf-native .evidence{animation:evreveal linear both;
    animation-timeline:view();animation-range:entry 10% entry 55%}
  @keyframes evreveal{from{opacity:0}to{opacity:1}}
}
@media(prefers-reduced-motion:reduce){
  .cf-native .evidence{animation:none;opacity:1}
}

/* ============================================================
   v14 · MEASURE AND RHYTHM - 2026-07-29
   Measured the whole of services.html at 1280 and every reading
   section came back identical: textW 920, left 172, right 188,
   nine times, with four of them within 3px of the same height.
   One measure repeated down a page is what "all sections alike"
   actually is, numerically. This layer gives the page three
   measures instead of one, and lets height follow from
   composition rather than from a constant.
   ============================================================ */

/* 1 · THE WIDE MEASURE
   The split is the only place the argument sits beside a picture,
   so it earns a wider frame than the reading column. 920 -> 1160
   is a visible step at any viewport over ~1200 without becoming
   a second full-bleed - the breaker keeps that job. */
.split .wrap{max-width:1160px}

/* The fold marker lives at -92px in the margin of a 920 column.
   At 1160 that lands off-canvas, so on a split the marker comes
   inside and sits above the pair. Different treatment on purpose:
   the wide sections read as a different kind of block. */
@media(min-width:1021px){
  .split .foldstep::before{left:0;top:-38px}
  .split .foldstep::after{display:none}
}

/* Aspect-ratio 4/5 on a ~520px column is a 650px tall picture, which
   would out-shout a paper section. Cap it and let object-fit crop. */
.sp-media{max-height:540px}

/* 2 · THE NARROW MEASURE
   Openings and closings get less width and more air. A shorter line
   reads as a slower line, which is what a section opener wants. */
.section.narrow .wrap{max-width:720px}
.section.narrow{padding:clamp(84px,11vh,132px) 0}

/* 3 · VERTICAL RHYTHM
   .section was a flat 72px top and bottom everywhere. Paper and ink
   alternate down the page, so let the change of stock carry a change
   of pace: paper blocks breathe, ink blocks tighten. */
.section.paper,.section.paper2{padding:clamp(78px,10vh,116px) 0}
.split{padding:clamp(64px,9vh,112px) 0}

/* Two sections of the same stock touching is the flat spot the
   distance view kept showing. When it happens, close the seam so the
   pair reads as one longer movement instead of two equal ones. */
.section.paper + .section.paper,
.section.paper2 + .section.paper2{padding-top:0}
.section.paper + .section.paper > .wrap,
.section.paper2 + .section.paper2 > .wrap{
  border-top:1px dashed var(--crease,rgba(83,39,157,.22));padding-top:clamp(44px,6vh,72px)}

@media(max-width:860px){
  .split .wrap{max-width:920px}
  .sp-media{max-height:none}
  .section.narrow{padding:clamp(56px,8vh,88px) 0}
}

/* ============================================================
   v15 · SPLIT MEDIA FILLS ITS COLUMN - 2026-07-29
   Measured: media 432px sitting in a 490px grid column, so every
   split had a 58px dead strip beside the picture and the image
   floated left of its own slot. Cause was aspect-ratio plus the
   v14 max-height cap - the box shrinks to keep the ratio instead
   of filling. Drop the ratio inside a split and drive height
   directly; object-fit already crops, so nothing is distorted.
   ============================================================ */
.split .sp-media{aspect-ratio:auto;height:clamp(380px,50vh,560px);max-height:none;width:100%}
@media(max-width:860px){
  .split .sp-media{height:clamp(260px,38vh,360px)}
}

/* ============================================================
   v16 · A PICTURE NEEDS AN EDGE - 2026-07-29
   Viewed the five case studies whole, at 0.17 scale, and every
   split read as an empty block. The images were loading and
   correctly sized - measured 490x560, all complete - they were
   simply house-graded dark and sitting on an ink field with no
   boundary between them. Up close it reads; at a glance the page
   looks like it has holes in it. That is the gap that is visible
   from across the room.
   The brand language already had the answer: paper laid on a dark
   desk has an edge and casts a shadow. Give it both, and lift the
   picture just enough to separate from the field it sits on.
   ============================================================ */
.split:not(.paper):not(.paper2) .sp-media{
  box-shadow:0 0 0 1px var(--crease-dark,rgba(180,156,225,.26)),0 24px 58px rgba(0,0,0,.55)}
.split:not(.paper):not(.paper2) .sp-media img.bk-img{filter:brightness(1.14) contrast(1.05)}
/* on paper the picture is laid ON the sheet, so it only needs the shadow */
.split.paper .sp-media,.split.paper2 .sp-media{
  box-shadow:0 0 0 1px rgba(19,17,30,.10),0 20px 44px rgba(19,17,30,.24)}

/* ============================================================
   v17 · THE PICTURE HOLDS WHILE THE ARGUMENT SCROLLS - 2026-07-29
   Measured on work-pageone: the split section is 946px tall
   because the argument is a long list, but the picture is 380px
   and centred, so it floats in the middle of a column that is
   283px empty above it and 283px below. A short picture beside a
   long list is a dead column, not a composition.
   Pin it instead. The sheet stays on the desk while the reader
   works down the page beside it, which is also the one thing the
   page was missing: something that actually moves with scroll and
   is not a decorative parallax.
   position:sticky needs no clipping ancestor, and .section carries
   a global overflow:hidden, so splits opt out. Safe because the
   image crop is clipped by .sp-media itself, not by the section.
   ============================================================ */
@media(min-width:861px){
  main .section.split{overflow:visible}
  .split .wrap{align-items:start}
  .split .sp-media{position:sticky;top:clamp(84px,11vh,128px)}
}
@media(prefers-reduced-motion:reduce){
  .split .sp-media{position:static}
}

/* ============================================================
   v18 · THE PAPER MOUNT - 2026-07-29
   The real finding from viewing whole pages at 0.17 scale: a
   house-graded photograph on an ink section has no boundary, so
   it reads as a hole in the page rather than a picture. Measured
   luminance told the same story - slate-vein sits at 0.08 against
   an ink field of 0.07. Invisible, by the numbers.
   A hairline border cannot fix a distance problem; at that scale
   1px is a fifth of a pixel. So mount the picture instead. On an
   ink section the photograph is a print on paper card: light mat,
   deeper at the foot, caption letterpressed into the mount, the
   corner turned like every other sheet on this site. The mat is
   what carries across the room; the picture is what rewards
   walking up to it.
   Note the image is absolutely positioned, so its containing
   block is the PADDING box - padding alone would be covered.
   The insets are restated to hold the mat open.
   ============================================================ */
.split:not(.paper):not(.paper2) .sp-media{
  background:var(--paper,#F0EDF5);
  padding:14px 14px 42px;
  box-shadow:0 26px 62px rgba(0,0,0,.58)}
/* An <img> is a REPLACED element: with position:absolute and width:auto it
   takes its INTRINSIC size, not the box the four insets describe. Setting
   left/right/top/bottom alone left a 1200x1797 photograph inside a 490x560
   mount, so every mounted picture clipped to blank card. Replaced elements
   need the size stated. Percentages resolve against the padding box, which is
   exactly the mount, so the mat is just subtracted back off. */
.split:not(.paper):not(.paper2) .sp-media img.bk-img{
  top:14px;left:14px;right:auto;bottom:auto;
  width:calc(100% - 28px);height:calc(100% - 56px);
  min-height:0;max-width:none;filter:none}
/* the turned corner is cut from the mount, so it wants ink not violet */
.split:not(.paper):not(.paper2) .sp-media::after{
  background:linear-gradient(225deg,var(--indigo,#53279D) 0 50%,transparent 50.5%);opacity:.9}
/* caption sits in the mount, printed, not overlaid on the picture */
.split:not(.paper):not(.paper2) .sp-cap{
  background:none;color:var(--ink,#13111E);opacity:.66;
  padding:0 16px 15px;line-height:1.3}
@media(max-width:860px){
  .split:not(.paper):not(.paper2) .sp-media{padding:10px 10px 34px}
  .split:not(.paper):not(.paper2) .sp-media img.bk-img{
    top:10px;left:10px;right:auto;bottom:auto;
    width:calc(100% - 20px);height:calc(100% - 44px)}
}

/* ============================================================
   v19 · EVERY PICTURE GETS AN EDGE - 2026-07-29
   The mount fixed dark photographs on ink. It does nothing for
   LIGHT ones: crane-flight samples at 205/255, so inside a paper
   mat it merges into one white block, and crane-hang at 196 does
   the same thing laid on a paper section. The mount solved one
   half of the problem and revealed the other.
   A mounted print always has a visible line where the paper stops
   and the image begins. Draw it. One hairline, on every standalone
   photograph, on both stocks - so the edge never depends on how
   bright the picture happens to be.
   ============================================================ */
.sp-media img.bk-img{box-shadow:0 0 0 1px rgba(19,17,30,.22)}
.split.paper .sp-media,.split.paper2 .sp-media{
  box-shadow:0 0 0 1px rgba(19,17,30,.16),0 20px 44px rgba(19,17,30,.24)}

/* ============================================================
   v20 · A PALE PICTURE IS NOT MOUNTED - 2026-07-29
   Second time learning the same lesson: a 1px rule cannot solve a
   problem you can only see at 0.155 scale, because 1px is a sixth
   of a pixel there. The v16 border failed for that reason and the
   v19 hairline failed again for pale images.
   The mount exists to lift a DARK photograph off a dark field.
   A pale one already carries on its own, and wrapping it in a
   light mat merges picture and card into exactly the white blob
   the mount was invented to prevent. So pale pictures go straight
   onto the ink, edge to edge, and keep the overlaid caption.
   Marked explicitly in the markup because CSS cannot see
   luminance; _check.html is what tells you which ones qualify.
   ============================================================ */
/* the v18 mount selector carries :not(.paper):not(.paper2), so these have to
   match that specificity or the mount simply keeps winning */
.split:not(.paper):not(.paper2) .sp-media.light{background:none;padding:0;
  box-shadow:0 26px 62px rgba(0,0,0,.5)}
.split:not(.paper):not(.paper2) .sp-media.light img.bk-img{
  top:0;left:0;right:auto;bottom:auto;width:100%;height:100%;box-shadow:none}
.split:not(.paper):not(.paper2) .sp-media.light .sp-cap{
  background:linear-gradient(transparent,rgba(19,17,30,.85));
  color:rgba(240,237,245,.92);padding:16px 18px;opacity:1}

/* ============================================================
   v21 · NO PARALLAX INSIDE A STICKY MOUNT - 2026-07-29
   REAL BUG, introduced by v17 and caught only by viewing a page
   at 1:1 after the whole-page screenshots kept disagreeing with
   the DOM. The mount rendered - card, turned corner, letterpressed
   caption - but the photograph never painted, and the compositor
   wedged hard enough that requestAnimationFrame stopped firing.
   Cause: `.bk-img` carries a scroll-driven parallax on
   `animation-timeline:view()`, and v17 put its container into
   `position:sticky`. The timeline measures where the element sits
   in the scrollport; sticky decides where it sits FROM the scroll.
   Each depends on the other, and Chrome thrashes resolving it.
   The parallax was written for a full-bleed breaker whose image
   overflows its frame by 14% top and bottom - slack a mounted
   picture does not have anyway. Splits get their motion from the
   sticky mount, which is the better effect regardless.
   ============================================================ */
.cf-native .sp-media img.bk-img{animation:none;transform:none}

/* v21b · DIAGNOSTIC: sticky off. NOTE static removes the containing block and
   sends the absolutely positioned image and caption to a different ancestor -
   relative is the correct "sticky off" state. */
@media(min-width:861px){
  .split .sp-media{position:relative;top:auto}
}

/* ============================================================
   v22 · THE MOUNT, REBUILT AS A BORDER - 2026-07-29
   The padding-based mount was the wrong mechanism. Because the
   picture is absolutely positioned, its containing block is the
   PADDING box, so the mat had to be subtracted back off with
   calc() - and that combination (abs-positioned replaced element,
   calc width/height, inside a clip-path'd overflow-hidden box)
   painted its box-shadow but never its bitmap. Verified the file
   itself is fine by opening the jpg directly.
   A border sits OUTSIDE the padding box, so the picture can just
   fill 100%/100% with no arithmetic and the frame is simply there.
   Same look, no calc, nothing to get wrong.
   ============================================================ */
.split:not(.paper):not(.paper2) .sp-media{
  background:var(--paper,#F0EDF5);
  border:14px solid var(--paper,#F0EDF5);
  border-bottom-width:42px;
  padding:0;
  box-sizing:border-box}
.split:not(.paper):not(.paper2) .sp-media img.bk-img{
  top:0;left:0;right:auto;bottom:auto;
  width:100%;height:100%;
  min-height:0;max-width:none;filter:none}
/* caption rides the foot of the picture; the mat below it is the mount */
.split:not(.paper):not(.paper2) .sp-cap{
  background:linear-gradient(transparent,rgba(19,17,30,.82));
  color:rgba(240,237,245,.92);opacity:1;padding:16px 16px 12px}
/* v17's sticky mount is WITHDRAWN, not disabled by accident.
   Pinning the picture put a scroll-driven `view()` timeline inside a
   position:sticky box, and the two define each other: the timeline measures
   where the element sits in the scrollport, sticky derives that from scroll.
   Chrome wedged on it - the section h2 stopped painting and rAF stopped
   firing altogether. The composition still works without it because the
   grid is align-items:start, so the picture tops out with the argument
   instead of floating in the middle of a long column.
   Do not reintroduce sticky here without also removing the parallax
   timeline from every descendant. */
@media(min-width:861px){
  .split .sp-media{position:relative;top:auto}
}

/* the pale-picture variant has to clear the BORDER now, not the padding -
   otherwise the mat survives as a paper-coloured frame it does not want */
.split:not(.paper):not(.paper2) .sp-media.light{
  background:none;border:0;padding:0}
.split:not(.paper):not(.paper2) .sp-media.light img.bk-img{
  top:0;left:0;width:100%;height:100%;box-shadow:none}

/* ============================================================
   v23 · ONE SIZING RULE FOR EVERY SPLIT PICTURE - 2026-07-29
   v22 fixed the ink-stock mounts but the PAPER-stock splits were
   still inheriting the breaker's sizing: left/right:0 with
   top:-8%/bottom:-8% AND height:100%, which is over-constrained.
   That works on a full-bleed breaker and does not work inside a
   clipped, fixed-height split frame - same empty card, caption
   showing, bitmap missing.
   The negative insets exist to give a parallax somewhere to
   travel. Split pictures do not parallax (see v21), so they do
   not need the slack. Size them plainly, on every stock.
   ============================================================ */
.split .sp-media img.bk-img{
  top:0;left:0;right:auto;bottom:auto;
  width:100%;height:100%;min-height:0;max-width:none}

/* ============================================================
   v24 · CLIP-PATH AND AN ABSOLUTE IMAGE DO NOT MIX - 2026-07-30
   Found on the LIVE site, not locally. A photograph inside a
   clip-path'd container simply never rasterised: the mount, its
   turned corner, its caption and even the image's own box-shadow
   all painted, but the bitmap did not. Every measurement said the
   element was perfect - loaded, sized, opaque, topmost, real pixel
   data on a canvas sample - and a plain <img> injected into the
   same page rendered fine. Setting clip-path:none inline made the
   photograph appear instantly.
   Local had fewer compositing layers so it survived; live adds the
   admin bar, a chat widget and a fixed nav and it does not. That
   makes it a latent bug rather than an environment quirk, so
   remove the cause instead of tuning around it.
   The turned corner is unaffected: ::after already draws the fold
   triangle over that corner, which is what carries the motif.
   Applies to BOTH containers that hold an absolute .bk-img.
   ============================================================ */
/* RESTORED 2026-07-30. clip-path was wrongly blamed for the unpainted images:
   removing it inline "fixed" them only because ANY inline style change forces a
   repaint, and the real cause was deferred decoding (F37). The corner CUT is a
   signature detail of this design - a real notch showing the section behind,
   not just a triangle drawn on top - so it goes back. */

/* ============================================================
   v25 · THE FOLD BUTTON - 2026-07-30
   Danish's idea: a button in the nav that looks like it does
   something, and every time you press it a sheet of paper folds
   itself into something different, in 3D, on the top layer.
   Built with real CSS 3D planes rotating about real creases -
   no library. The site's whole vocabulary is already creases and
   facets, so this is the brand doing a trick rather than a
   generic WebGL widget bolted onto it.
   ============================================================ */

/* --- the button: a small sheet with a lifted corner --- */
.foldbtn{
  position:relative;display:inline-flex;align-items:center;gap:8px;
  background:none;border:1px solid var(--crease,rgba(83,39,157,.34));
  color:var(--soft,#B49CE1);font-family:var(--mono);font-size:11px;
  letter-spacing:2px;text-transform:uppercase;
  padding:9px 14px 9px 12px;border-radius:6px;cursor:pointer;
  overflow:hidden;transition:color .3s,border-color .3s,transform .3s}
.foldbtn .fb-sheet{
  width:14px;height:14px;flex:0 0 14px;background:currentColor;
  clip-path:polygon(0 0,100% 0,100% 62%,62% 100%,0 100%);
  transition:clip-path .45s cubic-bezier(.2,.7,.3,1),transform .45s}
/* the shimmer that says "press me" - a slow crease of light crossing the
   button, not a gradient sweep; it should read as paper catching a lamp */
.foldbtn::after{
  content:"";position:absolute;top:-60%;left:-40%;width:34%;height:220%;
  background:linear-gradient(90deg,transparent,rgba(180,156,225,.5),transparent);
  transform:rotate(18deg);animation:fbshine 4.6s ease-in-out infinite;
  pointer-events:none}
@keyframes fbshine{0%,68%{left:-40%}88%,100%{left:120%}}
.foldbtn:hover,.foldbtn:focus-visible{
  color:var(--paper,#F0EDF5);border-color:var(--indigo-p,#7C52C7);transform:translateY(-1px)}
.foldbtn:hover .fb-sheet{clip-path:polygon(0 0,100% 0,100% 34%,34% 100%,0 100%);transform:rotate(-8deg)}
@media(prefers-reduced-motion:reduce){.foldbtn::after{animation:none;opacity:0}}
/* The nav gets tight before it collapses, so the label goes and the sheet
   glyph carries it. NOT display:none - this is the most alive thing on the
   site and phones should get it too. */
@media(max-width:1120px){
  .foldbtn{padding:8px;gap:0}
  .foldbtn .fb-label{display:none}
}
@media(max-width:820px){
  .foldbtn{position:absolute;right:64px;top:50%;transform:translateY(-50%);z-index:3}
  .foldbtn:hover,.foldbtn:focus-visible{transform:translateY(-50%)}
}

/* --- the overlay --- */
.foldshow{
  position:fixed;inset:0;z-index:9999;display:grid;place-content:center;
  background:rgba(10,9,16,.86);backdrop-filter:blur(9px) saturate(.7);
  opacity:0;visibility:hidden;transition:opacity .4s ease,visibility .4s;
  cursor:pointer;text-align:center}
.foldshow.fs-on{opacity:1;visibility:visible}
.fs-close{
  position:fixed;top:22px;right:24px;background:none;border:0;cursor:pointer;
  color:var(--soft-dark,rgba(180,156,225,.7));font-family:var(--mono);
  font-size:11px;letter-spacing:2px;text-transform:uppercase;padding:10px}
.fs-close:hover{color:var(--paper,#F0EDF5)}

.fs-stage{
  width:min(58vmin,340px);aspect-ratio:1;position:relative;margin:0 auto;
  perspective:900px;perspective-origin:50% 45%}

/* the crease pattern is scored first, then the paper folds along it */
.fs-creases{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.fs-c{fill:none;stroke-linecap:round;stroke-dasharray:var(--len,600);
  stroke-dashoffset:var(--len,600);animation:fsdraw .5s ease forwards}
.fs-m{stroke:rgba(180,156,225,.5);stroke-width:1}
.fs-v{stroke:rgba(124,82,199,.45);stroke-width:.8;stroke-dasharray:4 7;
  opacity:0;animation:fsfade .4s ease .12s forwards}
@keyframes fsdraw{to{stroke-dashoffset:0}}
@keyframes fsfade{to{opacity:1}}
/* once the paper starts folding the pattern is no longer needed */
.fs-creases{animation:fscreasesout .5s ease 1.15s forwards}
@keyframes fscreasesout{to{opacity:0}}

.fs-paper{position:absolute;inset:0;transform-style:preserve-3d;
  animation:fsturn 22s linear 1.5s infinite}
@keyframes fsturn{from{transform:rotateY(0)}to{transform:rotateY(360deg)}}

/* The RESTING state is the finished object, and the animation only adds the
   fold on top. If style recalc stalls - which it demonstrably does on this
   stack (see F37) - you still get a correctly folded origami, just without
   watching it fold. An effect that fails to a blank screen is not an effect. */
.fs-facet{
  position:absolute;inset:0;display:block;
  clip-path:var(--c);transform-origin:var(--o);
  backface-visibility:visible;
  opacity:1;transform:var(--t);
  animation:fsfold .85s cubic-bezier(.22,.9,.28,1) var(--d,.4s) both}
@keyframes fsfold{
  from{opacity:0;transform:rotate3d(var(--a),108deg)}
  60%{opacity:1}
  to{opacity:1;transform:rotate3d(var(--a),0deg) var(--t)}
}
/* four paper tones so adjacent facets read as facing different ways.
   Flat white planes look like a diagram; slightly different greys look
   like an object with a light source. */
/* Two-sided paper. --pc is the sheet colour, set per fold in JS.
   t0/t1 are the WHITE reverse catching the light; t2/t3 are the COLOURED
   face, shaded by how far it has turned away. That contrast between the two
   sides is what makes a folded thing read as folded - flat grey facets just
   look like a technical diagram, which is what this was before. */
.fs-t0{background:linear-gradient(145deg,#FFFFFF,color-mix(in srgb,var(--pc,#53279D) 7%,#FFFFFF))}
.fs-t1{background:linear-gradient(145deg,color-mix(in srgb,var(--pc,#53279D) 10%,#FFFFFF),
                                        color-mix(in srgb,var(--pc,#53279D) 26%,#FFFFFF))}
.fs-t2{background:linear-gradient(145deg,color-mix(in srgb,var(--pc,#53279D) 86%,#FFFFFF),var(--pc,#53279D))}
.fs-t3{background:linear-gradient(145deg,var(--pc,#53279D),color-mix(in srgb,var(--pc,#53279D) 58%,#000000))}
/* a hairline where two facets meet, so creases stay legible at any angle */
.fs-facet{box-shadow:0 0 0 .5px rgba(19,17,30,.16)}
/* the sheet colour is named under the form name, like a materials note */
.fs-paper-name{display:block;margin-top:7px;font-size:11px;letter-spacing:2.5px;
  color:var(--soft-dark,rgba(180,156,225,.5));text-transform:uppercase}

.fs-name{
  margin:34px 0 6px;font-family:var(--mono);font-size:12.5px;letter-spacing:5px;
  color:var(--paper,#F0EDF5);opacity:1;animation:fsin .5s ease 1.5s backwards}
.fs-hint{
  margin:0;font-family:var(--mono);font-size:11px;letter-spacing:2px;
  color:var(--soft-dark,rgba(180,156,225,.55));opacity:1;
  animation:fsin .5s ease 2s backwards}
@keyframes fsin{from{opacity:0}to{opacity:1}}

/* reduced motion: no spin, no fold, just show the finished object */
.foldshow.fs-still .fs-paper{animation:none}
.foldshow.fs-still .fs-facet{animation:none;opacity:1;transform:var(--t)}
.foldshow.fs-still .fs-creases{animation:none;opacity:.25}
.foldshow.fs-still .fs-name,.foldshow.fs-still .fs-hint{animation:none;opacity:1}
@media(prefers-reduced-motion:reduce){
  .fs-paper{animation:none}
  .fs-facet{animation:none;opacity:1;transform:var(--t)}
  .fs-creases{animation:none;opacity:.25}
  .fs-name,.fs-hint{animation:none;opacity:1}
}

/* ============================================================
   v26 · INVISIBLE BUTTON TEXT - 2026-07-30
   Danish found this on his phone and he was right: "Tell me
   what's broken" was an empty purple slab.

   `.section.paper a` scores (0,2,1). `.btn` scores (0,1,0). So on
   every paper or paper2 section the link colour beat the button
   colour and a solid indigo button rendered indigo text on an
   indigo background - contrast 1.00, measured. Not a near miss,
   literally the same colour.
   This is site-wide, not one page: any .btn inside a light section
   was affected. Scope the button colours so they always outrank
   the section link colour rather than tying with it.
   ============================================================ */
.section.paper a.btn,.section.paper2 a.btn,
.paper a.btn,.paper2 a.btn,.statband a.btn{color:#fff}
.section.paper a.btn.ghost,.section.paper2 a.btn.ghost,
.paper a.btn.ghost,.paper2 a.btn.ghost{color:var(--ink)}
.section.paper a.btn.ghost:hover,.section.paper2 a.btn.ghost:hover,
.paper a.btn.ghost:hover,.paper2 a.btn.ghost:hover{color:var(--indigo-d)}
/* same trap, same shape: the pullquote and breaker copy are dark surfaces */
.breaker a.btn,.pullquote a.btn,.finalcta a.btn{color:#fff}

/* the fold button was resolving --soft to a dim grey (#6B6580, 3.37:1).
   State the colour instead of inheriting a token that changes under it. */
.foldbtn{color:#B49CE1}
.foldbtn:hover,.foldbtn:focus-visible{color:#F0EDF5}

/* ============================================================
   v27 · TAP TARGETS - 2026-07-30
   Measured every interactive element at 393px. Layout was already
   sound (no overflow, splits stack, no dead links) but several
   controls were well under the 44px minimum - the footer nav was
   17px tall, which on a phone is a coin toss whether you hit it.
   Danish reviews on a phone; this is the difference between the
   site feeling built and feeling fiddly.
   Padding, not font-size: the type scale is deliberate and should
   not change just to win a tap target.
   ============================================================ */
@media(max-width:900px){
  /* footer nav row - the worst offender, and on every page */
  footer .r a{display:inline-block;padding:14px 6px;line-height:1.15}
  footer .r{display:flex;flex-wrap:wrap;gap:2px 10px;align-items:center}
  /* homepage figure links */
  .figure a{display:inline-block;padding:12px 0}
  /* any standalone link that is its own block needs a thumb-sized row */
  .lead + a,.wrap > a:not(.btn):not(.mark):not(.navcta){display:inline-block;padding:11px 0}
  /* .selfref is the "the Crease Pattern" style cross-reference - a standalone
     line of link text, so it gets a thumb row like any other control */
  .selfref a{display:inline-block;padding:10px 0;line-height:1.3}
  /* the fold button needs a real thumb target, not a 32px chip */
  .foldbtn{min-width:44px;min-height:44px;justify-content:center;padding:0 12px}
}
/* the fold glyph should grow a little with the bigger button */
@media(max-width:820px){
  .foldbtn .fb-sheet{width:16px;height:16px;flex-basis:16px}
}

/* ============================================================
   v29 · ANIMATION AUDIT FIXES - 2026-07-30
   Audited all 22 keyframes. The good news first: every one of
   them animates only opacity, transform or stroke-dashoffset, so
   nothing in this design triggers layout on a frame. That is the
   part that usually goes wrong and it was already right.

   Four animations run INFINITELY, and two of those were costing
   real work on a phone every second the page was open:

   1. .cpbg::before drifted a repeating pattern with
      background-position. Background-position is not composited -
      it repaints the whole layer every frame, forever, on a
      full-bleed element. Same look, driven by transform instead.
      The pattern tiles at 180px so translating exactly 180px is
      seamless; the pseudo is oversized so no edge is ever exposed.

   2. .foldbtn::after animated `left`. That is a layout property,
      infinitely, on every page - my own bug, introduced with the
      fold button. Now a transform.

   Also: .scrollcue is already display:none under 820px so its
   pulse never runs on a phone, and both infinite decorations now
   stop for prefers-reduced-motion.
   ============================================================ */
.cpbg::before{inset:-180px -180px 0 -180px;background-position:0 0}
@keyframes cpdrift2{
  from{transform:translate3d(0,0,0)}
  to{transform:translate3d(180px,180px,0)}
}
.cpbg::before{animation:cpdrift2 90s linear infinite}

.foldbtn::after{left:-40%;animation:fbshine2 4.6s ease-in-out infinite}
@keyframes fbshine2{
  0%,68%{transform:rotate(18deg) translateX(0)}
  88%,100%{transform:rotate(18deg) translateX(470%)}
}

@media(prefers-reduced-motion:reduce){
  .cpbg::before{animation:none;transform:none}
  .scrollcue::after{animation:none;opacity:.7;transform:none}
  .foldbtn::after{animation:none;opacity:0}
}

/* ============================================================
   v30 · DON'T PAY FOR DECORATION ON A PHONE - 2026-07-30
   Counted the running animations on the-method: 77, of which 61
   are `creasedraw` on the decorative crease-field SVG lines.
   stroke-dashoffset is a PAINT property, not composited, so each
   one invalidates paint on every frame it is in range. On desktop
   that is free; on a mid-range phone, sixty of them during a
   scroll is exactly where jank comes from.
   The crease fields are background texture at low opacity - at
   phone size the drawing gesture is barely perceptible anyway. So
   below 900px the lines are simply THERE, fully drawn, with no
   animation. The art survives; the per-frame cost does not.
   Desktop keeps the full drawing behaviour.
   ============================================================ */
@media(max-width:900px){
  .cf-native .cfield line,.cf-native .cfield rect,.cf-native .cfield polygon,
  .cf-native .fd-line,.cfield line,.cfield rect,.cfield polygon,.fd-line{
    animation:none !important;
    stroke-dashoffset:0 !important}
}

/* ============================================================
   v31 · THE BACK OF THE PAPER - 2026-07-30
   Danish: "either the object should not rotate or it should look
   proper from the back too, currently it's only the front."
   Correct, and the reason is physical. A sheet of origami paper
   has a coloured side and a white side. A facet showing you its
   coloured face MUST show white when you walk behind it. Before
   this, every facet showed the same fill from both sides, so the
   far half of the object looked painted rather than folded.
   So each facet now has a real reverse: ::after, rotated 180deg
   about Y so it registers with the front, carrying the OPPOSITE
   side of the sheet. backface-visibility hides whichever one is
   facing away, and the parent's clip-path shapes both, so the
   silhouette stays identical from either direction.
   ============================================================ */
.fs-facet{backface-visibility:hidden}
.fs-facet::after{
  content:"";position:absolute;inset:0;
  transform:rotateY(180deg);
  backface-visibility:hidden;
  box-shadow:0 0 0 .5px rgba(19,17,30,.14)}
/* the reverse of each tone, i.e. the other side of the same sheet */
.fs-b0::after{background:linear-gradient(215deg,#FFFFFF,color-mix(in srgb,var(--pc,#53279D) 7%,#FFFFFF))}
.fs-b1::after{background:linear-gradient(215deg,color-mix(in srgb,var(--pc,#53279D) 10%,#FFFFFF),
                                                color-mix(in srgb,var(--pc,#53279D) 26%,#FFFFFF))}
.fs-b2::after{background:linear-gradient(215deg,color-mix(in srgb,var(--pc,#53279D) 86%,#FFFFFF),var(--pc,#53279D))}
.fs-b3::after{background:linear-gradient(215deg,var(--pc,#53279D),color-mix(in srgb,var(--pc,#53279D) 58%,#000000))}

/* the spin is now driven by tapping the paper, so it needs a cursor that says
   the paper is the control and the surround is something else */
.fs-stage{cursor:pointer}
.fs-hint{max-width:32ch;margin-left:auto;margin-right:auto;line-height:1.7}
/* the colour label is gone - the object names itself and nothing else */
.fs-paper-name{display:none}

/* ============================================================
   v32 · THE FOLD BUTTON, PROPERLY - 2026-07-30
   Two fair criticisms from Danish: the placement was a "loose
   fit" and the icon was boring. The measurements agreed - the
   button sat 251px from the CTA cluster, floating in dead space
   between the links and the right-hand group, because .navindex
   carries the margin-left:auto that pushes that group right.

   Placement: the fold button now LEADS the right-hand cluster, so
   the three controls read as one group instead of one orphan and
   a pair.

   Icon: a clipped square said nothing. It is now three of the
   actual silhouettes the overlay folds - crane, plane, star -
   cross-fading, so the icon literally previews the behaviour:
   press this and you get one of these, and not the same one
   twice. Opacity only, so it costs nothing to run.
   ============================================================ */
.foldbtn{margin-left:auto;position:relative;border-radius:999px;
  width:auto;padding:0 15px;height:38px;gap:0}
.nav .navindex{margin-left:0}          /* the cluster is anchored by .foldbtn now */

.fb-glyph{width:20px;height:20px;overflow:visible;display:block}
/* Three silhouettes sharing one 8.4s cycle. The first attempt used POSITIVE
   delays and a window narrower than the slot, which left roughly 1.3s in every
   cycle where all three sat at opacity 0 - an empty button. Caught it in a
   screenshot that happened to land in the gap.
   Negative delays start each glyph already part-way through its own cycle, so
   all three are live from the first frame, and the visible window (0-36% plus
   the 96-100% fade-in) is deliberately WIDER than the 33.3% slot so consecutive
   glyphs overlap instead of leaving a hole. */
.fb-glyph .fbg{fill:currentColor;
  animation:fbcycle 8.4s ease-in-out infinite}
.fb-glyph .fbg1{animation-delay:0s}
.fb-glyph .fbg2{animation-delay:-5.6s}
.fb-glyph .fbg3{animation-delay:-2.8s}
@keyframes fbcycle{
  0%,30%{opacity:1}
  36%,96%{opacity:0}
  100%{opacity:1}}

/* a soft indigo bloom behind the glyph - this is the one control on the site
   that does something purely for pleasure, so it is allowed to glow */
.fb-halo{position:absolute;inset:-1px;border-radius:inherit;pointer-events:none;
  background:radial-gradient(circle at 50% 50%,rgba(124,82,199,.42),transparent 68%);
  opacity:.5;transition:opacity .35s}
.foldbtn:hover .fb-halo,.foldbtn:focus-visible .fb-halo{opacity:1}
.foldbtn:hover .fb-glyph{transform:rotate(-8deg) scale(1.06);transition:transform .35s cubic-bezier(.2,.7,.3,1)}

@media(prefers-reduced-motion:reduce){
  .fb-glyph .fbg{animation:none;opacity:0}
  .fb-glyph .fbg1{opacity:1}          /* hold one silhouette, no cycling */
  .foldbtn:hover .fb-glyph{transform:none}
}
@media(max-width:1120px){
  .foldbtn{padding:0 12px}
}
@media(max-width:820px){
  /* in the phone header it sits left of the hamburger, tight, thumb sized */
  .foldbtn{position:absolute;right:62px;top:50%;transform:translateY(-50%);
    width:44px;height:44px;padding:0;justify-content:center;margin-left:0}
  .foldbtn:hover,.foldbtn:focus-visible{transform:translateY(-50%)}
}

/* v33 · the market card's category line is a deliberate mono micro-label, but
   12px is genuinely hard on a phone. Nudge it, keep the character. */
@media(max-width:900px){
  .mvibe{font-size:12.5px;letter-spacing:1.4px}
}

/* ============================================================
   v34 · THE MARKET CARDS NEED A DEEPER SCRIM - 2026-07-30
   Seen at 1:1, not caught by the automated contrast pass - that
   probe compares text against a walked-up background colour, which
   is meaningless when the text sits on a photograph.
   The old scrim reached only 0.55 opacity at the midpoint, which is
   where the mono subtitle sits. Over Vancouver's bright sky and the
   Las Vegas neon those lines were close to unreadable.
   Deepen the lower half where every line of text lives, and LIGHTEN
   the top so more of the photograph survives. Better contrast and a
   better composition at the same time: picture up top, words below.
   ============================================================ */
/* Corrected. The first attempt moved the ramp DOWN the card, which made the
   subtitle position lighter (0.43) than the original (0.47) - I darkened the
   wrong band. Measured against where the text actually sits: the tag line is
   about 32% down, the vibe line 44%, the description 50-75%. So the scrim has
   to be near-solid by 38% and stay there. The top 18% still shows the
   photograph cleanly, which is all the picture needs to do here. */
.market::after{
  background:linear-gradient(180deg,
    rgba(19,17,30,.16) 0%,
    rgba(19,17,30,.46) 18%,
    rgba(19,17,30,.86) 38%,
    rgba(19,17,30,.95) 62%,
    rgba(19,17,30,.97) 100%)}
.market .mvibe{color:#CDBCF2;opacity:1}
.market .mtag{color:#C5AEF5}
/* a phone shows the cards stacked and shorter, so the text zone is a bigger
   share of the card - push the dark up further still */
@media(max-width:820px){
  .market::after{background:linear-gradient(180deg,
    rgba(19,17,30,.30) 0%,
    rgba(19,17,30,.66) 34%,
    rgba(19,17,30,.92) 62%,
    rgba(19,17,30,.97) 100%)}
}

/* ============================================================
   v35 · THE PHONE HERO, AND THE NAV CLUSTER THAT WAS OVERLAPPING
   Judged on a real 393px viewport, logged out, against the brotli
   cache bucket - i.e. the page Danish actually gets. Three bugs
   that the desktop view completely hides.
   ============================================================ */

/* 1. The crane was a ghost on the phone.
   The desktop hero is a HORIZONTAL composition: solid ink 0-32% where the
   text lives, opening to .28 by 82% where the crane lives. The crane gets a
   genuine window. The mobile override replaced that with a flat vertical
   scrim at .92/.82/.74 - heavy everywhere, so the crane got a window
   nowhere. It read as grey diagonal smear, which is worse than no photo:
   an unrecognisable object reads as a rendering fault.

   Tried and rejected, in this order: crane below the text (the hero is 858px
   and the fold is at 852, so the clear band is only 108px - the body needs
   238); crane large in the bottom band (collides with the statband and eats
   "3 COUNTRIES"). Both failed for the same structural reason - at 393px the
   copy is full-width and dense, so there is no region where the crane can be
   a SUBJECT. Accepting that, the honest treatment is a lift: let it read
   clearly as folded paper across the whole hero.

   Contrast measured on the composited result, not assumed. Worst case per
   element: kicker 7.91, h1 10.63, sub 5.49 (needs 4.5), ghost button 7.00. */
@media(max-width:760px){
  .homehero.cine::after{
    background:
      linear-gradient(180deg,
        rgba(19,17,30,.90) 0%,
        rgba(19,17,30,.78) 40%,
        rgba(19,17,30,.66) 68%,
        rgba(19,17,30,.72) 86%,
        rgba(19,17,30,.92) 100%),
      url("img/hero-crane.jpg") !important;
    background-size:cover, cover !important;
    background-position:center, 62% 50% !important;
    background-repeat:no-repeat !important}
}

/* 2. The fold button was sitting ON TOP of the hamburger.
   .foldbtn was absolutely positioned at a hard-coded right:62px while
   .navtoggle sat in normal flow - two different placement systems, so they
   only ever lined up at the one width the 62px was eyeballed at. Measured
   overlap: 10px x 36px at 760, 2px at 393. The hamburger's tap target won,
   so tapping the right edge of the fold button opened the menu instead.

   Fixed by putting both in the flex flow and letting the nav's existing
   gap:12px do the spacing. Ordered explicitly because the DOM order is
   mark, navtoggle, links, foldbtn - the hamburger comes FIRST in markup but
   must sit LAST visually. Selector is .nav .foldbtn (0,2,0), not .foldbtn
   (0,1,0), because the absolute rules above it are .foldbtn and would
   otherwise keep their transform - the same specificity trap as the
   invisible buttons in v26. */
@media(max-width:820px){
  .nav .mark{order:1}
  .nav .foldbtn{order:2;position:static;margin-left:auto;
    width:44px;height:44px;padding:0;justify-content:center;
    transform:none;top:auto;right:auto}
  .nav .foldbtn:hover,.nav .foldbtn:focus-visible{transform:none}
  .nav .navtoggle{order:3;margin-left:0}
  .nav .links{order:4}
}

/* 3. The kicker split its own phrase.
   At 393px "Origami Digital - Folded with intent" broke after FOLDED,
   leaving "WITH INTENT" alone on line two. In letter-spaced caps a
   mid-phrase break reads as a mistake. Keep the second phrase whole so the
   break can only happen at the separator, which is where it belongs. */
.kicker .nbw{white-space:nowrap}

/* ============================================================
   v36 · /work/ HAD UNREADABLE BODY COPY AT EVERY WIDTH
   ============================================================
   Found by compositing the hero photo under its own gradient and
   computing the contrast ratio per text box, rather than looking at it.
   The .sub on /work/ measured 1.45:1 against a required 4.5:1 - the same
   order as the invisible-button bug, and for the same reason: it looked
   atmospheric, so nobody checked the number.

   cranes-flight.jpg is a PALE photograph. The 96deg gradient opened to
   .42 alpha at 66% of the width, which on desktop was meant to fall to the
   right of the copy - but .sub is max-width:62ch, so the column grows with
   the viewport and runs straight through that bright window. Measured:

     width   current   angled+shifted   vertical
      393      1.45         -             5.78
      600      1.46         -             5.70
      900      1.61        2.58           5.76
     1100      1.64        3.58           5.70
     1440       -          5.39           5.63

   So this was never a phone bug - it failed on desktop too, and only the
   1440 column was ever clear. Shifting the angle does not rescue it,
   because the thing that moves is the text, not the window. The vertical
   scrim is the only one that holds across the range, so it replaces the
   angled one entirely rather than being hidden behind a media query. */
.hero.folds::after{
  background:
    linear-gradient(180deg,
      rgba(19,17,30,.92) 0%,
      rgba(19,17,30,.90) 34%,
      rgba(19,17,30,.88) 64%,
      rgba(19,17,30,.80) 88%,
      rgba(19,17,30,.70) 100%),
    url("img/cranes-flight.jpg") center center/cover no-repeat}

/* ============================================================
   v37 · CAPTION SCRIMS FADED IN THE WRONG UNITS
   ============================================================
   .sp-cap sits on the photograph and carried
   `linear-gradient(transparent, rgba(19,17,30,.8))` - a ramp measured as a
   PERCENTAGE of the caption box. That is fine for a one-line caption, where
   the text is near the bottom and the scrim is nearly full there. It fails
   for a three-line caption: measured on /services/, the box is 51px tall
   with 16px of top padding, so the first line sits between 25% and 55%
   alpha - over crane-in-hand.jpg that is around 1.4:1, against a required
   4.5:1. The caption gets less readable the more it has to say, which is
   exactly backwards.

   The fade belongs to the PADDING, not to the box: anchor it in px so the
   scrim is already at full strength wherever the first line begins, however
   many lines follow. Same reason the mount border in v22 is a border and
   not a calc - fixed things should be expressed in fixed units. */
.sp-cap,
.split:not(.paper):not(.paper2) .sp-media.light .sp-cap,
.split:not(.paper):not(.paper2) .sp-cap{
  background:linear-gradient(180deg,
    rgba(19,17,30,0) 0px,
    rgba(19,17,30,.90) 16px,
    rgba(19,17,30,.95) 100%)}

/* ============================================================
   v38 · THE FOLD TOY WAS RENDERING ONE FACE OUT OF FOUR
   ============================================================
   v31 gave every facet a back face - `.fs-facet::after` rotated 180deg with
   its own reverse paper tone - so the origami would look right from behind,
   which is what Danish asked for. It made things worse, and I shipped it
   without opening the overlay to look.

   `.fs-facet` was left at the default `transform-style: flat`. A flat
   element does not establish a 3D context for its children, so the
   ::after's rotateY(180deg) was FLATTENED into the facet's own plane
   instead of becoming a plane facing the other way. Both faces then shared
   one facing direction - and since v31 also set `backface-visibility:hidden`
   on both, the moment a facet turned away from the camera BOTH of its faces
   were culled and the facet vanished outright.

   Measured on the live BOX: 4 facets in the DOM, all opacity 1, all with
   bright gradients (one at luminance 1.0) over a 0.003-luminance backdrop,
   paper rotating normally - and one white sliver on screen. The model was
   perfect and three quarters of it was invisible.

   The rule: an element that needs a two-sided ::after must itself be
   preserve-3d. Perspective on the stage and preserve-3d on the parent are
   not enough; the flattening happens at the facet.

   Worth naming the near-miss: the CDP screenshots showed NOTHING at all,
   which looked like the F39 stalled-raster problem and nearly had me
   dismiss it as a tooling artifact. Opening it in an ordinary tab at 1:1 -
   F39's own prescription - is what showed the single surviving sliver and
   proved the bug was real. */
.fs-facet{transform-style:preserve-3d}

/* ============================================================
   v39 · CORRECTING v38, AND TWO CHANGES THAT DO HOLD UP
   ============================================================
   v38 claimed `.fs-facet{transform-style:preserve-3d}` fixed the fold toy.
   It does not, and the claim was made on bad evidence. Two errors:

   1. `clip-path` is a grouping property. Per CSS Transforms, an element with
      clip-path (or filter, mask, opacity<1) has its transform-style USED
      value forced to `flat` no matter what is declared. Every facet has
      `clip-path:var(--c)`, so preserve-3d on a facet is inert - and v31's
      whole ::after back-face design cannot work while the clip-path is
      there. getComputedStyle reports the COMPUTED value ("preserve-3d"),
      not the used one, so the check I ran confirmed nothing. Same trap
      family as F39: the API answered a different question than I asked.

   2. The BOX that rendered correctly right after v38 was a lucky rotation
      angle, not the fix. One screenshot at one moment of a 22s spin is not
      evidence. FISH at other angles still shows one facet out of five.

   v38's line is left in place because it is harmless, not because it works.

   What DOES hold up, and why:

   a) The spin was `rotateY(0 -> 360deg)` with no tilt, and these forms are
      near-flat cut-outs with only +/-17deg of facet tilt. So twice per
      revolution the entire model passes exactly edge-on and disappears.
      Adding a constant rotateX takes the projected paper width at the worst
      angle from 6px to 113px - measured, not guessed.

   b) With the ::after back face unable to work (see 1), a facet with
      `backface-visibility:hidden` has NOTHING to show once it turns away,
      so it vanishes rather than showing its reverse. Until the facet
      architecture is rebuilt without clip-path, a facet must keep painting
      its front when turned away. A slightly wrong tone beats a hole.

   Neither of these makes the toy right - several forms still read as
   fragments at many angles, because the forms themselves are flat cut-outs
   rather than solids. That is a geometry rebuild (real translateZ depth,
   or SVG polygons instead of clip-path so the back faces work), and it is
   not something to guess at unverified. Left for a session with a
   trustworthy visual loop. */
@keyframes fsturn{
  from{transform:rotateX(-18deg) rotateY(0)}
  to  {transform:rotateX(-18deg) rotateY(360deg)}
}
.fs-facet{backface-visibility:visible}

/* ============================================================
   v40 · THE HOMEPAGE HERO FAILED ACROSS THE WHOLE TABLET BAND
   ============================================================
   Two things to record here, because the second one is the lesson.

   THE BUG. The desktop hero gradient opens to .42 at 66% and .28 at 82% so
   the crane gets a clear window on the right. That is tuned for 1440, where
   the 1280-max wrap leaves the copy well clear of it. Between roughly 761px
   and 1240px the wrap narrows but the crane - sized `auto 118%` of hero
   HEIGHT, not width - does not narrow with it, so the photograph slides in
   under the text. Measured worst-case contrast:

     width   before   after
      780     1.89     6.11
      900      -       7.26
     1024     3.48     6.93
     1150     2.96     7.80
     1240     7.80     7.80   (already fine, unchanged)

   1.89:1 is not "a bit low", it is unreadable. Nobody had looked at this
   site at 800px, because the review loop was phone and 1440 and nothing in
   between.

   THE MEASUREMENT ERROR, which nearly hid it. My first desktop sweep
   reported 4.35 at 1024 - marginal, easy to wave through. It was wrong: the
   probe assumed `background-size: cover` while this hero actually uses
   `auto 118%`, so it composited the photo at the wrong scale and sampled
   the wrong pixels. Once the probe honoured the real background-size the
   true figure was 3.48, and 1.89 at 780. A contrast probe that does not
   replicate background-size EXACTLY is not measuring the page. Same family
   as F40: the instrument was the thing that was wrong.

   The fix keeps the composition rather than flattening it - text still sits
   on ink at the left, the crane still has its window at the right, the
   window just starts later and stays darker until the copy has ended.
   A vertical scrim was also tested and passed, but only at 4.75-5.40 and it
   throws away the left-to-right idea the desktop hero is built on. */
@media(min-width:761px) and (max-width:1240px){
  .homehero.cine::after{
    background:
      linear-gradient(90deg, var(--ink) 0%, var(--ink) 38%,
        rgba(19,17,30,.95) 56%, rgba(19,17,30,.84) 74%,
        rgba(19,17,30,.66) 88%, rgba(19,17,30,.74) 100%),
      linear-gradient(180deg, rgba(19,17,30,.55) 0%, transparent 18%,
        transparent 76%, var(--ink) 100%),
      url("img/hero-crane.jpg");
    background-size:cover,cover,auto 118%;
    background-position:center,center,96% 45%;
    background-repeat:no-repeat}
}

/* ============================================================
   v41 · /about/ - THE LAST HERO STILL UNDER THE LINE
   ============================================================
   Across a 99-combination sweep (11 pages x 9 widths from 360 to 1440),
   /about/ was the only page left failing, and only just: the kicker measured
   4.47 at 780px and 4.46 at 900px against a required 4.5. It sat between
   4.46 and 4.84 at EVERY width, which is the real signal - not one bad
   breakpoint but a hero that never had any margin to begin with, so any
   photograph, font or colour change would have tipped it over.

   `hands-folding.jpg` is the brightest interior hero and the 96deg gradient
   only reached .55 at its open end. Taking that to .72, with a mid stop at
   .87, puts the page at 5.95-6.19 across the range - real headroom rather
   than a number that happens to round the right way today. */
.hero.hands::after{
  background:linear-gradient(96deg,
    rgba(19,17,30,.96) 30%,
    rgba(19,17,30,.87) 64%,
    rgba(19,17,30,.72) 100%),
  url("img/hands-folding.jpg") right center/cover}

/* ============================================================
   v42 · THE FOLD TOY, ACTUALLY FIXED - SHAPES OFF clip-path
   ============================================================
   v38 and v39 both failed to fix this because both assumed the problem was
   backface culling. It was not. Isolated by forcing every facet opaque
   magenta with the spin frozen, then changing one variable at a time:

     clip-path on, facets coplanar      1 of 5 facets painted
     clip-path on, 25px apart in z      3 of 5 painted
     clip-path OFF entirely             5 of 5 painted
     backface-visibility forced visible  no change at all

   So `clip-path` was the cause, and backface-visibility was never involved.
   Two separate things go wrong with it: it is a GROUPING property, so the
   facet's transform-style is forced to used-value `flat` (which is why the
   ::after back faces of v31 could never paint); and Chrome collapses
   coplanar clip-path'd planes inside a preserve-3d parent so only one of
   them survives. These facets are all `inset:0` on the same box with small
   tilts, i.e. maximally coplanar - the worst case for that bug.

   The silhouette now comes from an inline `<svg><polygon>` inside each
   facet. That is ordinary painted content, not a grouping property, so the
   facet stays a genuine 3D plane and every facet paints. The polygon
   numbers are the same ones, reformatted from `10% 50%` to `10,50`.

   Consequences handled here: the tone gradients move from the facet's
   background to the polygon's fill; the hairline crease moves from the
   facet's box-shadow (which without a clip would draw a full RECTANGLE) to
   the polygon's stroke, non-scaling so it stays a hairline at any depth. */
.fs-facet{clip-path:none;background:none;box-shadow:none}
.fs-facet > svg{position:absolute;inset:0;width:100%;height:100%;display:block;overflow:visible}
.fs-facet polygon{
  stroke:rgba(19,17,30,.28);stroke-width:1;vector-effect:non-scaling-stroke;
  stroke-linejoin:round}
/* the same two-sided paper as before, as fills rather than backgrounds */
.fs-t0 polygon{fill:#FFFFFF}
.fs-t1 polygon{fill:color-mix(in srgb,var(--pc,#53279D) 18%,#FFFFFF)}
.fs-t2 polygon{fill:color-mix(in srgb,var(--pc,#53279D) 86%,#FFFFFF)}
.fs-t3 polygon{fill:var(--pc,#53279D)}
/* v31's ::after back face is retired: it was a full RECTANGLE that only ever
   worked because the facet's clip-path shaped it, and the clip-path is gone.
   backface-visibility:visible (v39) keeps a turned-away facet showing its
   own tone, which is what paper does anyway. */
.fs-facet::after{display:none}

/* ============================================================
   v43 · TWO-SIDED PAPER, WHICH IS WHAT WAS ASKED FOR ORIGINALLY
   ============================================================
   Danish, on the fold toy: "either the object should not rotate or it should
   look proper from the back too, currently it's only the front." v31 tried to
   answer that with a rotated ::after and could not, because the facet carried
   a clip-path and a clip-path forces the element flat - the ::after was never
   a separate plane, so both faces shared one facing and the facet vanished
   whenever it turned away (F41).

   With v42 the silhouette comes from an SVG polygon instead, so the facet is
   a real 3D plane again and a true reverse face is finally possible. Each
   facet now holds TWO svgs with the same polygon: the second rotated 180deg
   about Y. backface-visibility hides whichever faces away, so exactly one
   paints at any angle and the silhouette is identical from both sides - which
   is how paper actually behaves.

   Verified on the live STAR before shipping: front at rotateY(-25deg) shows
   10 facets alternating violet and white; back at rotateY(158deg) shows the
   same 10, mirrored, with the tones swapped. Nothing drops out. */
.fs-facet{transform-style:preserve-3d}
.fs-facet > svg{position:absolute;inset:0;width:100%;height:100%;display:block;
  overflow:visible;backface-visibility:hidden}
.fs-facet > .fs-bk{transform:rotateY(180deg)}
/* front = the tone this facet shows the camera */
.fs-t0 .fs-fr polygon{fill:#FFFFFF}
.fs-t1 .fs-fr polygon{fill:color-mix(in srgb,var(--pc,#53279D) 18%,#FFFFFF)}
.fs-t2 .fs-fr polygon{fill:color-mix(in srgb,var(--pc,#53279D) 86%,#FFFFFF)}
.fs-t3 .fs-fr polygon{fill:var(--pc,#53279D)}
/* back = the OTHER side of the same sheet (0<->2, 1<->3, set in JS) */
.fs-b0 .fs-bk polygon{fill:#FFFFFF}
.fs-b1 .fs-bk polygon{fill:color-mix(in srgb,var(--pc,#53279D) 18%,#FFFFFF)}
.fs-b2 .fs-bk polygon{fill:color-mix(in srgb,var(--pc,#53279D) 86%,#FFFFFF)}
.fs-b3 .fs-bk polygon{fill:var(--pc,#53279D)}

/* ============================================================
   v44 · THE DESIGN VOCABULARY, AND ONE REAL MISALIGNMENT
   ============================================================
   Danish: not satisfied with the design and finesse of what is live. He was
   right, and the reason turned out to be measurable rather than a matter of
   taste.

   THE VOCABULARY. The stylesheet was carrying 28 distinct fixed font sizes -
   NINETEEN of them between 10px and 20px - plus 18 different clamp()
   expressions, and 20 different border-radius values including 99px, 100px
   and 999px all meaning "pill". Nobody can see the difference between 12px
   and 12.5px, or between a 9px and a 10px corner. What they can see is that
   nothing in the page sits on a shared rhythm, and that reads as assembled
   rather than designed. Two nearly-identical display sizes (83.52px and
   86.4px) were rendering side by side on the homepage.

   Snapped onto a real scale by value substitution only - no selector, rule or
   structural change, verified by identical brace and declaration counts
   before and after:

     font-size   28 -> 13 fixed steps
     clamp()     18 -> 9 display intentions
     radius      20 -> 5 (2 hairline / 6 chip / 10 card / 16 panel / 999 pill)

   THE MISALIGNMENT. The three market cards bottom-align their content
   (justify-content:flex-end), so a card whose description runs one line
   shorter starts one line lower. Vancouver's description is 3 lines where
   Manchester's and Las Vegas's are 4, which dropped its city name exactly
   24px below the other two - visible on a three-up row, and the sort of
   thing that quietly costs credibility.

   min-height on the description was the obvious fix and it is the wrong one:
   it is a floor, not an equaliser, so it held at 1280 and 1440 and failed at
   880, 960, 1024 and 1600 where the copy re-wraps longer. Anchoring the text
   block to the TOP and pinning the CTA to the bottom with an auto margin
   makes both edges independent of line count. Measured title spread and CTA
   spread are 0px at every width from 880 to 1600. */
.markets .market{justify-content:flex-start}
.markets .mnum{margin-bottom:clamp(56px,7vw,104px)}
.markets .mgo{margin-top:auto}

/* ============================================================
   v45 · TWO LABELS THAT WERE EFFECTIVELY INVISIBLE
   ============================================================
   Found by compositing every text box that sits over a photograph against
   that photograph plus its scrim, across all 11 pages - 78 boxes checked.
   Two real defects came out of it. (The .pcard readings in the same sweep
   were false positives: that text sits on the browser-frame's opaque
   rgb(244,242,248), not on the screenshot behind it.)

   1 · THE MARKET CARD NUMBERS. "01 / 02 / 03" sit at the TOP of each city
   card, which is exactly where the card scrim is weakest (.16 rising to .46),
   directly over the photograph. Measured contrast 1.01 to 1.11 against a
   required 4.5 - they were not faint, they were gone.

   Fixed locally rather than by darkening the whole top band, because that
   band is the only place the city photograph is visible at all. A small chip
   carries the number: 8.20 to 16.27 across the three cards. align-self is
   the load-bearing part - .mnum is a flex child, so without it the chip
   stretches the full width of the card and reads as a bar.

   2 · THE BREAKER EYEBROWS. .bk-kicker measured 1.50 over man-roofs.jpg.
   The copy block is bottom-aligned, and the vertical scrim only reaches
   ~.28 alpha where the eyebrow lands, over a bright sky (backdrop luminance
   .243). No colour fixes that on its own - even pure white tops out at 3.58.

   A panel behind the copy was tried first and rejected on looks: it reads as
   a card bolted onto the photograph, and its rounded corner against the sky
   pulls the eye to the box instead of the words. Bringing the existing
   vertical ramp up earlier does the same job with no edge anywhere, and
   costs the photograph almost nothing because the top half - the part you
   actually see past the copy - is untouched:

                        eyebrow   statement   photo top half
     current              1.50       3.30         0.115
     earlier ramp         4.93       8.98         0.100
     + brighter lilac     7.59         -            -

   The statement line was itself marginal at 3.30 against a required 3.0, so
   this fixes that too. The eyebrow keeps its lilac; it is one tint lighter. */
.markets .mnum{align-self:flex-start;background:rgba(19,17,30,.66);
  border:1px solid rgba(180,156,225,.30);border-radius:6px;padding:4px 10px;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);color:#F0EDF5}
.breaker::after{background:linear-gradient(180deg,
  rgba(19,17,30,.30) 0%,rgba(19,17,30,.22) 34%,rgba(19,17,30,.80) 48%,
  rgba(19,17,30,.90) 66%,rgba(19,17,30,.95) 100%)}
.bk-kicker{color:#D6C9F4}
/* the light variant is the same shape in paper, so its dark copy keeps a
   light backdrop at the same point in the ramp */
.breaker.light::after{background:linear-gradient(180deg,
  rgba(240,237,245,.10) 0%,rgba(240,237,245,.22) 34%,rgba(240,237,245,.80) 48%,
  rgba(240,237,245,.90) 66%,rgba(240,237,245,.95) 100%)}
.breaker.light .bk-kicker{color:var(--indigo)}

/* ============================================================
   v46 · A SIXTH FOLD, AND THE CHIP THAT WAS MISSING FOR IT
   ============================================================
   Services grew a fold. Danish designs and builds whole sites - a clinic
   marketing brand, a charitable hospital, an agency flagship, a client
   reporting portal - and the page sold only the search work, while its own
   sub-line disclaimed "web design theatre". So there is now a FOLD 01, "the
   sheet itself", before anything gets folded, and the five existing folds
   shift down by one.

   The chips deepen in purple across the sequence and were keyed by attribute
   for FOLD 02 through 05 only. FOLD 06 already existed on the-method and had
   been rendering at the base tone the whole time, so this closes a real gap
   rather than only serving the new section. */
.foldstep[data-fold="FOLD 06"]::before{background:rgba(83,39,157,.56);color:#B49CE1}

/* ============================================================
   v47 - STATEMENT: the crease pattern spans the statement
   ------------------------------------------------------------
   The graphic sat in column 2 as a fixed 426px square, centred over a 582px
   text stack. Centring is not the problem; the problem is that a square in a
   taller column leaves ~120px of empty right column beside the foot-note, and
   an unfilled wireframe box floating in a void reads as a broken image rather
   than as a drawing.

   Stretching it to the full row span makes it exactly as tall as the words it
   sits beside, which is also what the metaphor wants: the map behind the copy.
   A square that tall is wider than its column, so it bleeds right into the
   section's existing `overflow:hidden`, and the text is lifted above it.

   Opacity .5 -> .62: at .5 the 1px non-scaling strokes on near-black were
   under the threshold where the eye resolves them as a pattern at all.
   ============================================================ */
@media(min-width:901px){
  .statement .wide{align-items:center}
  .statement .smark,
  .statement .big,
  .statement .foot-note{position:relative;z-index:2}
  .creasegraphic{
    align-self:stretch;
    justify-self:end;
    width:auto;height:100%;
    max-width:none;
    margin-right:clamp(-96px,-5vw,-40px);
    opacity:.62;
    z-index:0;
  }
}

/* ============================================================
   v48 - REFUSED: five cards, one width
   ------------------------------------------------------------
   .flats is `flex-wrap` with `flex:1 1 250px`, so the last row's leftovers
   grow to fill it. With five cards that put three at 283px above two at 430px:
   the same component at two widths inside one set, which reads as unresolved
   rather than as a deliberate 3+2.

   A 6-track grid with every card spanning 2 makes all five identical, and the
   orphan row centres itself by starting at track 2. The 4-track variant does
   the same for the 2-up range.

   These spans assume FIVE cards. Adding a sixth makes the nth-child rules
   wrong, and the fix is to drop them, not to add more. Noted here because the
   next person to add a refused fold will not read the changelog.
   ============================================================ */
@media(min-width:1000px){
  .refused .flats{display:grid;grid-template-columns:repeat(6,1fr);gap:20px}
  .refused .flat{grid-column:span 2}
  .refused .flat:nth-child(4){grid-column:2/span 2}
  .refused .flat:nth-child(5){grid-column:4/span 2}
}
@media(min-width:640px) and (max-width:999px){
  .refused .flats{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
  .refused .flat{grid-column:span 2}
  .refused .flat:nth-child(5){grid-column:2/span 2}
}

/* ============================================================
   v49 - FOOTER: mass that earns its place
   ------------------------------------------------------------
   The footer was one 153px band: mark, a brand line, and five nav links that
   duplicated the header. Thin, and doing no work.

   The audit had the real reason to change it. Case studies carried 2 to 4
   inbound internal links each while every nav page carried 11, and the footer
   offered no route to them at all - on a site whose entire argument IS the case
   studies. Listing all six gives the footer legitimate height and fixes the
   link distribution at the same time, which is the only kind of footer bulk
   worth adding.

   Three columns on desktop, stacking to one. The link lists are `display:grid`
   rather than inline separated by dots, so the six case names read as a column
   and no separator character has to be invented.
   ============================================================ */
.foot .inner{max-width:1120px;align-items:start;gap:34px 48px}
.foot .fh{display:block;font-family:var(--mono);font-size:11px;letter-spacing:2px;
  text-transform:uppercase;color:var(--soft);margin-bottom:12px}
.foot .c,.foot .r{display:grid;gap:7px;font-size:14.5px;line-height:1.5}
.foot .c a,.foot .r a{color:var(--indigo-p)}
.foot .c a:hover,.foot .r a:hover{color:var(--paper)}
.foot .r{margin-left:auto;text-align:right;justify-items:end}
.foot .fdom{margin-top:10px;color:var(--soft);font-family:var(--mono);font-size:12px;letter-spacing:.5px}
.foot .l{flex:1 1 260px;max-width:340px}
/* Below 820 the three columns become a grid, not a flex column. Two reasons.
   `.foot .l` carries `flex:1 1 260px`, and in a COLUMN flex container that
   basis is a HEIGHT, so the brand block claimed 260px and grew from there;
   the footer measured 997px on a 393px screen. And stacking all three in one
   column is the wrong shape anyway: the two link lists are short and narrow
   and belong side by side, which halves the height again. */
@media(max-width:820px){
  .foot .inner{display:grid;grid-template-columns:1fr 1fr;gap:28px 20px;align-items:start}
  .foot svg,.foot .l{grid-column:1/-1}
  .foot .l{max-width:none;flex:0 0 auto}
  .foot .c{grid-column:1}
  .foot .r{grid-column:2;margin-left:0;text-align:left;justify-items:start}
}
@media(max-width:420px){
  .foot .inner{grid-template-columns:1fr}
  .foot .c,.foot .r{grid-column:1}
}
/* Below 560 the case-study column comes out. Not because it is too tall in
   pixels, but because every footer link is a 44px tap target by rule, so
   eleven of them is 825px of footer on a phone. That is a design problem, not
   a CSS one, and the honest fix is to list fewer things rather than to shrink
   the targets. Work is still in Sheets and leads to all six.
   The markup is unchanged, so the links are still in the HTML on every page
   and the internal link distribution the footer was added to fix is intact. */
@media(max-width:560px){
  .foot .c{display:none}
}

/* ============================================================
   v50 - the decorative crease field stops reserving 760px of blank page
   ------------------------------------------------------------
   `.cfield-wrap{position:absolute}` is what makes the injected crease field a
   pure overlay. But line 342 says

       .section.paper > *,.section.paper2 > *{position:relative;z-index:1}

   which is specificity (0,2,1) against the wrap's (0,1,0). On any .paper or
   .paper2 section the overlay lost, became a flow element, and reserved its
   own 760px box below the last real content.

   origami-fold.js appends that field to the LAST section of every page, so
   four pages ended with three quarters of a screen of blank paper before the
   footer: /work/, /about/, /contact/ and the homepage. It reads as "the page
   just ends with a lot of space", which is exactly the kind of fault eyes
   excuse and geometry does not.

   Equal specificity, declared later, so the overlay wins back.
   ============================================================ */
.section.paper > .cfield-wrap,
.section.paper2 > .cfield-wrap{position:absolute}

/* v1.12 · statband row two sits centered instead of sprawling full width with an
   empty right half per card */
.figure.s3{grid-column:span 2}
.figure.s3:nth-child(4){grid-column:2/span 2}
@media(max-width:900px){.figure.s3:nth-child(4){grid-column:span 1}}

/* v1.12 · the Vegas market plate graded darker than its siblings; lift it to match
   Manchester and Vancouver at card crop */
.market[href$="work.html"] .bgimg,.market[href$="/work/"] .bgimg{filter:brightness(1.3) saturate(1.06)}

/* v1.12 · at 1150-1400px the six links + index + fold + cta squeeze Contact onto a
   second row; tighten link padding in that band so the row holds on one line */
@media(min-width:901px) and (max-width:1420px){
  .nav .links a{padding:10px 9px;font-size:15px}
  .nav .navcta{padding-left:14px;padding-right:14px;letter-spacing:1.4px}
  .nav{gap:8px}
}

/* ---------------------------------------------------------------
   PROOF DECK, v1.13

   The evidence cards are real dashboard screenshots: mostly white, mostly
   chrome, and on a page this dark a full-height one reads as a slab of glare
   rather than a screen. Cropping to the top of each capture keeps the part that
   carries the number, shortens the deck, and lets the card behave like a window
   onto a tool instead of a photograph of one. The fade at the cut edge is what
   stops the crop reading as a mistake.
   --------------------------------------------------------------- */
.pcard{overflow:hidden}
.pcard .shot{position:relative;border-radius:10px;overflow:hidden;display:block}
.pcard .shot img{display:block;width:100%;height:auto;max-height:clamp(240px,38vh,400px);
  object-fit:cover;object-position:top center;border-radius:10px}
.pcard .shot::after{content:"";position:absolute;left:0;right:0;bottom:0;height:56px;
  background:linear-gradient(to bottom,rgba(244,242,248,0),rgba(244,242,248,.96));pointer-events:none}
@media(max-width:860px){
  .pcard .shot img{max-height:none}
  .pcard .shot::after{display:none}
}
