/* ===========================================================================
   Selected work 2026 — the qlub and Spemai case studies.

   These two pages carry their own design, taken from Figma: Poppins, Iris
   (#7d00d4), soft radial grounds, and cards with a 50px radius behind a white
   5px rim. It is deliberately not the rest of the site's language, which is
   Inter on a hairline grid — a case study is allowed to look like the product
   it is about. The site's header, footer and behaviour are unchanged, so the
   page still belongs to the site even while it looks like itself.

   Built to the Figma frame at 1240px and reflowed below it; every colour,
   radius, weight and gap here is the value from the file.
   =========================================================================== */

@font-face{font-family:'Poppins';font-style:normal;font-weight:300;font-display:swap;src:url(assets/fonts/poppins-300.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url(assets/fonts/poppins-400.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url(assets/fonts/poppins-500.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url(assets/fonts/poppins-600.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:700;font-display:swap;src:url(assets/fonts/poppins-700.woff2) format('woff2')}

.wk{
  --iris:#7d00d4;
  --ink:#202020;
  --body:#444;
  --muted:#616161;
  --quiet:#878787;
  --rim:#fff;
  --card-r:50px;
  /* Spemai runs on the same page furniture in its own green */
  --jade:#23a078;
  --jade-ink:#11312a;
  --jade-deep:#0c5b4a;
  --jade-label:#878787;
  --jade-body:#292929;

  /* One scale for both case studies. qlub was set at the frame's own pixel
     sizes and Spemai's reading copy was scaled with --px like its artwork,
     so the same paragraph came out 16px on one page and 13px on the other.
     Type that is read is sized from here on both; only the mockups still
     scale with the column. */
  --fs-h2:20px;    --lh-h2:28px;   /* a section's heading */
  --fs-h3:18px;    --lh-h3:24px;   /* a sub-heading */
  --fs-label:16px; --lh-label:26px;/* the small coloured labels */
  --fs-body:13px;  --lh-body:21px; /* paragraphs, list items, kickers */

  /* And one set of gaps. Several of these were stated in frame pixels scaled
     by --px, so at the site's narrower column they came out about a third
     smaller than drawn -- which is why the pages read compact, and why Spemai
     read tighter than qlub. Space between sections is not artwork, so it is
     set against the viewport instead. */
  --gap-chapter:clamp(76px,11vw,140px); /* between chapters */
  --gap-section:clamp(46px,6.4vw,84px); /* between sections within one */
  --gap-figure:clamp(22px,3vw,38px);    /* a figure under the note for it */
  font-family:'Poppins',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  color:var(--ink);
}
/* The frame's own ground: white at the top, a wash of lilac through the middle. */
.wk-page{
  background:radial-gradient(120% 90% at 50% 36%,#fff 3%,#faf4ff 48%,#fefcff 100%);
  padding:0 0 clamp(40px,5vw,72px);
}
/* The frame is 1240 wide with 60px insets, so the column of content is
   exactly 1120 -- the width of the rules in the file. */
/* One column for the whole case study, on the site's own 816 -- text and
   figures share it, which is what lets a heading line up with the screen it
   introduces, and the page sits on the same measure as every other page.
   Drawing the mockups at the frame's 1120 instead meant the browser enlarging
   them past what the files hold, which is what read as pixelation; on this
   column they land at roughly their own resolution. --px converts a frame
   pixel into its share of the column. */
.wk-wrap{max-width:816px;margin:0 auto;padding:0 var(--pad);container-type:inline-size;--px:calc(100cqw / 1120)}
.wk-rule{height:1px;background:var(--doc-line,#e9e2ef);border:0;margin:calc(var(--gap-section) * .8) 0}

/* --- opening --- */
.wk-brand{display:block;height:51px;width:auto;margin-bottom:39px}
.wk-eyebrow{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#000}
.wk-lede{margin-top:20px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

/* --- two columns of context --- */
.wk-cols{display:grid;grid-template-columns:minmax(0,418fr) minmax(0,494fr);gap:clamp(28px,calc(142 * var(--px)),142px);margin-top:var(--gap-section)}
.wk-col h2{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#000}
.wk-col p{margin-top:20px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

/* --- the regions line --- */
.wk-region{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.wk-region h2{font-size:var(--fs-h2);font-weight:600;line-height:var(--lh-h2);color:var(--iris)}
.wk-flags{font-size:24px;line-height:1.2;letter-spacing:2px}
.wk-region-note{margin-top:14px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

/* --- the bento of product areas ---
   Three columns on the frame: 312, 436 and 356 wide, with the middle column
   taller than the outer two. */
/* The frame's three columns. minmax(0,...) so a track can shrink below what
   its image would like to be -- otherwise one photograph sets the width of
   the whole row. */
.wk-bento{container-type:inline-size;--px:calc(100cqw / 1120);display:grid;grid-template-columns:minmax(0,312fr) minmax(0,436fr) minmax(0,356fr);gap:max(10px,calc(16 * var(--px)));margin-top:var(--gap-section);align-items:start}
.wk-bento-col{display:flex;flex-direction:column;gap:max(10px,calc(16 * var(--px)))}
.wk-card{position:relative;border:max(3px,calc(5 * var(--px))) solid var(--rim);border-radius:calc(50 * var(--px));overflow:hidden;background:#fff}
.wk-card img{display:block;width:100%;height:100%;object-fit:cover}
/* The photographs carry their caption at the foot, over a rise of black. */
.wk-card-photo{isolation:isolate}
.wk-card-photo::after{content:"";position:absolute;inset:0;background:linear-gradient(to top,rgba(0,0,0,.92) 18%,rgba(0,0,0,0) 56%);pointer-events:none}
.wk-card-body{position:absolute;left:calc(40 * var(--px));right:calc(32 * var(--px));bottom:calc(34 * var(--px));z-index:1;color:#fff}
.wk-card-body h3{font-size:max(17px,calc(24 * var(--px)));font-weight:600;line-height:1.33}
.wk-card-body p{margin-top:calc(12 * var(--px));font-size:max(12px,calc(14 * var(--px)));font-weight:400;line-height:1.43;color:rgba(255,255,255,.92)}

/* The opening tile: a lilac wash with a soft disc drifting behind the words. */
.wk-tile-intro{background:linear-gradient(205deg,#fff 21%,#f5e2fb 123%);min-height:calc(199 * var(--px));display:flex;align-items:center}
.wk-tile-intro .wk-blob{position:absolute;left:calc(-85 * var(--px));top:calc(50 * var(--px));width:calc(250 * var(--px));height:calc(240 * var(--px));transform:rotate(16deg);opacity:.9}
.wk-tile-intro h3{position:relative;padding:0 calc(40 * var(--px));font-size:max(18px,calc(28 * var(--px)));line-height:1.25;color:#000b52;font-weight:300}
.wk-tile-intro h3 b{font-weight:700}

/* The brand chip. */
.wk-tile-colour{background:var(--iris);min-height:calc(171 * var(--px));display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:#fff}
.wk-tile-colour span{font-size:max(16px,calc(24 * var(--px)));line-height:1.29}
.wk-tile-colour small{font-size:max(13px,calc(20 * var(--px)));color:rgba(255,255,255,.6)}

/* The logo tile. The artwork is far larger than the card and sits mostly
   outside it -- the frame insets are -91.42% left and -79.54% right, so it
   spans 271% of the tile's width and is cropped by it. */
.wk-tile-mark{background:linear-gradient(160deg,#a02bff 0%,#7d00d4 60%,#6a00b5 100%);aspect-ratio:436/384}
.wk-tile-mark img{position:absolute;left:-91.42%;top:-33.76%;width:270.96%;height:276.89%;max-width:none;object-fit:fill}

/* The warm tile behind the food photograph. */
/* A cut-out sitting on a warm ground, so the photograph keeps its alpha and
   the gradient shows through around it. */
.wk-tile-warm{background:radial-gradient(120% 120% at 50% 50%,#fff 0%,#ffe5cc 100%);aspect-ratio:356/275}
.wk-tile-warm img{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:78%;height:auto;object-fit:contain}

@media(max-width:780px){
.wk-cols{gap:34px}
.wk-bento{grid-template-columns:minmax(0,1fr) minmax(0,1fr);--px:calc(100cqw / 760)}
}
@media(max-width:600px){
.wk-cols{grid-template-columns:1fr;gap:28px}
.wk-bento{grid-template-columns:1fr;gap:14px;--px:calc(100cqw / 430)}
.wk-brand{height:40px;margin-bottom:26px}
}

/* --- page 2: the customer app --- */
.wk-block{margin-top:var(--gap-chapter)}
.wk-kicker{font-size:var(--fs-body);font-weight:600;line-height:var(--lh-label);color:var(--iris)}
.wk-h2{margin-top:16px;font-size:var(--fs-h2);font-weight:600;line-height:var(--lh-h2);color:#000;max-width:calc(700 * var(--px))}
.wk-h3{font-size:var(--fs-h2);font-weight:600;line-height:var(--lh-h2);color:#000}
.wk-p{margin-top:8px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}
.wk-p--tight{margin-top:12px;font-weight:400}
.wk-em{color:var(--iris);font-weight:500}

/* The stage the three phones stand on: a radial fall from #990bff to #1f0034,
   the frame's own stops. */
.wk-stage{position:relative;margin-top:var(--gap-figure);border-radius:calc(50 * var(--px));overflow:hidden;aspect-ratio:1121/661;
  background:radial-gradient(90% 130% at 50% 36%,#990bff 3%,#7b08cc 27%,#5c059a 52%,#3e0367 76%,#2e014e 88%,#1f0034 100%)}
.wk-phone{position:absolute;transform:var(--rest);border:max(3px,calc(7 * var(--px))) solid rgba(255,255,255,.4);border-radius:calc(40 * var(--px));overflow:hidden;background:#000}
.wk-phone img{display:block;width:100%;height:100%;object-fit:cover}
/* Centre phone: 218 x 551 of a 1121 x 661 frame, 335 from the top. */
.wk-phone--mid{left:50%;top:50%;width:19.45%;aspect-ratio:218/551;--rest:translate(-50%,-50%);box-shadow:0 4px 74px rgba(0,0,0,.08);z-index:2}
/* The two behind it are shorter and tipped 14.9 degrees out. */
.wk-phone--left{left:32.7%;top:49.8%;width:19.42%;aspect-ratio:218/471;--rest:translate(-50%,-50%) rotate(-14.9deg)}
.wk-phone--right{left:66.8%;top:49.8%;width:19.42%;aspect-ratio:218/471;--rest:translate(-50%,-50%) rotate(14.91deg);border-radius:calc(30 * var(--px))}

/* --- the two columns of detail --- */
.wk-two{display:grid;grid-template-columns:minmax(0,482fr) minmax(0,561fr);gap:clamp(30px,calc(78 * var(--px)),78px);align-items:start;margin-top:var(--gap-section)}
.wk-two h3,.wk-role h3{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#000}
.wk-two ul{margin-top:20px;padding-left:24px;color:var(--body);font-size:var(--fs-body)}
.wk-two li{line-height:var(--lh-body)}

.wk-role{margin-top:var(--gap-section)}
.wk-role p{margin-top:20px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

@media(max-width:700px){
.wk-two{grid-template-columns:1fr;gap:34px}
.wk-phone--left{left:28%}
.wk-phone--right{left:72%}
}
@media(max-width:560px){
.wk-stage{aspect-ratio:1121/560}
.wk-phone--mid{width:26%}
.wk-phone--left,.wk-phone--right{width:25%}
}

/* --- page 3: gift cards ---
   The panel is rebuilt at the frame's own pixel sizes, but the stage sets its
   font-size to a 1120th of its own width, so calc(1 * var(--px)) is one design pixel and the
   whole composition scales as one piece. A transform cannot do this in CSS
   alone: scale() needs a unitless number and a length cannot be divided by a
   length. */
.wk-stage-fixed{position:relative;container-type:inline-size;overflow:hidden;border-radius:calc(40 * var(--px));margin-top:var(--gap-figure)}
/* One design pixel, as a length. Geometry multiplies it; nothing inside
   depends on an inherited font-size, so a font-size declaration cannot
   change the meaning of the sizes beside it. */
.wk-fit{position:absolute;inset:0;--px:calc(100cqw / 1120)}

.wk-gift{aspect-ratio:1120/763;background:linear-gradient(187.92deg,#aa32ff 8.48%,#2c004a 92.95%)}
.wk-gift-glow{position:absolute;left:50%;top:calc(242 * var(--px));width:calc(404 * var(--px));height:calc(399 * var(--px));transform:translateX(-50%);opacity:.9}
/* Broad bands of light lying across the panel, at 5% white. */
.wk-gift-streak{position:absolute;background:rgba(255,255,255,.05)}
.wk-gift-s1{left:calc(-212 * var(--px));top:calc(-150 * var(--px));width:calc(299 * var(--px));height:calc(881 * var(--px));transform:rotate(16.14deg)}
.wk-gift-s2{left:calc(-219 * var(--px));top:calc(-324 * var(--px));width:calc(429 * var(--px));height:calc(1265 * var(--px));transform:rotate(11.19deg)}
.wk-gift-s3{left:calc(789 * var(--px));top:calc(-138 * var(--px));width:calc(292 * var(--px));height:calc(881 * var(--px));transform:rotate(-20deg)}
.wk-gift-s4{left:calc(701 * var(--px));top:calc(-146 * var(--px));width:calc(425 * var(--px));height:calc(881 * var(--px));transform:rotate(-13.77deg)}

.wk-gift-row{position:absolute;left:50%;top:calc(353 * var(--px));transform:translateX(-50%);display:flex;gap:calc(20 * var(--px));align-items:center}
.wk-gcard{position:relative;width:calc(280 * var(--px));height:calc(157 * var(--px));border-radius:calc(16 * var(--px));overflow:hidden;flex:none;font-family:'Inter','Poppins',sans-serif;color:#fff}
.wk-gcard--violet{background:linear-gradient(115.79deg,#a83bf3 0%,#c680f6 100%)}
.wk-gcard--peach{background:linear-gradient(115.79deg,#ff6797 0%,#ffe6d9 100%)}
.wk-gcard--pink{background:linear-gradient(115.79deg,#ef3a7c 0%,#ff90d0 100%)}
.wk-gcard-pattern{position:absolute;left:calc(50% - calc(18 * var(--px)));top:calc(50% - calc(1.5 * var(--px)));width:calc(386 * var(--px));height:calc(386 * var(--px));transform:translate(-50%,-50%) rotate(-90deg);mix-blend-mode:multiply;object-fit:cover}
.wk-gcard-veil{position:absolute;left:calc(50% - calc(18 * var(--px)));top:calc(50% - calc(1.5 * var(--px)));width:calc(386 * var(--px));height:calc(386 * var(--px));transform:translate(-50%,-50%);background:linear-gradient(224.75deg,rgba(255,255,255,0) 18.86%,rgba(255,255,255,.8) 33.56%,#fff 71.71%);mix-blend-mode:multiply}
.wk-gcard-logo{position:absolute;left:calc(14 * var(--px));top:calc(16 * var(--px));width:calc(58 * var(--px));height:calc(24 * var(--px))}
.wk-gcard-title{position:absolute;left:calc(16 * var(--px));top:calc(50% - calc(19.5 * var(--px)));font-size:calc(16 * var(--px));line-height:calc(20 * var(--px));font-weight:400;margin:0}
.wk-gcard-title b{font-weight:600}
.wk-gcard-valid{position:absolute;left:calc(16 * var(--px));top:calc(125 * var(--px));font-size:calc(10 * var(--px));line-height:normal}
.wk-gcard-valid b{font-weight:600}
.wk-gcard-art{position:absolute;pointer-events:none}
.wk-gcard-ellipse{position:absolute;left:calc(50% + calc(100 * var(--px)));top:calc(50% + .calc(5 * var(--px)));width:calc(236 * var(--px));height:calc(236 * var(--px));transform:translate(-50%,-50%)}
.wk-gcard--dark .wk-gcard-title,.wk-gcard--dark .wk-gcard-valid{color:#242424}
/* The brand tiles stacked on the first card, tipped ten degrees. */
.wk-gcard-tiles{position:absolute;left:calc(50% + calc(88.95 * var(--px)));top:calc(50% - calc(3.22 * var(--px)));width:calc(119 * var(--px));height:calc(262 * var(--px));transform:translate(-50%,-50%) rotate(10deg);display:grid;grid-template-columns:repeat(2,calc(54.6 * var(--px)));gap:calc(9.9 * var(--px));align-content:start}
.wk-gcard-tiles span{width:calc(54.6 * var(--px));height:calc(54.6 * var(--px));border-radius:calc(9.93 * var(--px));background:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden}
.wk-gcard-tiles img{max-width:75%;max-height:60%;object-fit:contain}
.wk-gcard-tiles::after{content:"";position:absolute;inset:0;background:linear-gradient(to bottom,#ba64f5 0%,rgba(192,115,246,0) 50%,#bc6cf4 100%)}

.wk-gift-phone{position:absolute;left:50%;top:calc(116 * var(--px));width:calc(467 * var(--px));height:calc(701 * var(--px));transform:translateX(-50%);object-fit:cover}
.wk-gift-head{position:absolute;left:50%;top:calc(60 * var(--px));width:calc(457 * var(--px));transform:translateX(-50%);text-align:center;color:#fff}
.wk-gift-head img{display:block;margin:0 auto;width:calc(85 * var(--px));height:calc(26 * var(--px))}
.wk-gift-head h2{margin-top:calc(4 * var(--px));font-size:calc(34 * var(--px));font-weight:500;line-height:calc(46 * var(--px))}
.wk-gift-head p{font-size:calc(16 * var(--px));font-weight:500;line-height:calc(32 * var(--px))}

/* --- the outcome strip ---
   The panels, icons and figure scale with the column; the two lines of prose
   keep a readable floor instead, since they are copy rather than artwork. */
/* Two panels from the frame: 376 + 744 on a 1120 column, each 172 tall, and
   the shape is one path rounded on its outer edge only, so the pair reads as a
   single pill with a seam down the middle. Everything is stated in frame
   pixels and scaled by --px, the way the mockup stages are, so the strip keeps
   its proportions at the site's column width. */
.wk-impact{container-type:inline-size;display:grid;grid-template-columns:minmax(0,376fr) minmax(0,744fr);gap:0;margin-top:var(--gap-section);--px:calc(100cqw / 1120)}
.wk-impact-cell{position:relative;aspect-ratio:376/172;display:flex;align-items:center;justify-content:center;color:#fff}
.wk-impact-cell--wide{aspect-ratio:744/172;justify-content:flex-start}
.wk-impact-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:fill}
/* the left panel is that same path mirrored, so its round corners fall on the
   outside and the flat edge meets the right panel */
.wk-impact-cell:first-child .wk-impact-bg{transform:scaleX(-1)}
.wk-impact-in{position:relative;display:flex;align-items:center;gap:calc(22 * var(--px))}
.wk-impact-in>div{text-align:center}
.wk-impact-in img{width:calc(43 * var(--px));height:calc(64 * var(--px));object-fit:contain;flex:none}
.wk-impact-in img:first-child{transform:scaleX(-1)}
.wk-impact-num{font-size:max(34px,calc(54 * var(--px)));font-weight:600;line-height:1;letter-spacing:calc(-1 * var(--px))}
.wk-impact-cap{margin-top:calc(6 * var(--px));font-size:max(12px,calc(16 * var(--px)));line-height:1.2;letter-spacing:calc(-.32 * var(--px));white-space:nowrap}
.wk-impact-copy{position:relative;padding-left:calc(40 * var(--px));max-width:calc(599 * var(--px))}
.wk-impact-copy p:first-child{font-size:max(13px,calc(14 * var(--px)));font-weight:400;line-height:1.5;opacity:.85}
.wk-impact-copy p:last-child{margin-top:calc(10 * var(--px));font-size:max(16px,calc(20 * var(--px)));font-weight:600;line-height:1.25}
@media(max-width:700px){
/* stacked, so each panel gets the round corners on both ends */
.wk-impact{grid-template-columns:1fr;gap:10px;--px:calc(100cqw / 560)}
.wk-impact-cell,.wk-impact-cell--wide{aspect-ratio:376/172;justify-content:center}
.wk-impact-bg{border-radius:20px;background:linear-gradient(90deg,#aa32ff,#7d00d4)}
.wk-impact-cell:first-child .wk-impact-bg,.wk-impact-cell--wide .wk-impact-bg{display:none}
.wk-impact-cell{border-radius:20px;overflow:hidden;background:linear-gradient(101deg,#aa32ff 0%,#6a00b4 100%)}
.wk-impact-cell--wide{background:linear-gradient(101deg,#6a00b4 0%,#2c004a 100%)}
.wk-impact-copy{padding:0 calc(28 * var(--px));max-width:none;text-align:center}
.wk-impact-in{gap:calc(26 * var(--px))}
}

/* --- the strip above the case study ---
   It used to sit outside the case study on the site's own texture, which left
   a visible seam where the page's ground began, and on the 816px column while
   the case study ran wider. It now sits inside the ground, on the same column,
   so the two line up and the background runs through in one piece. */
.wk-top{max-width:816px;margin:0 auto clamp(26px,4vw,56px);padding:0 var(--pad)}
.wk-top .cs-top{font-family:'Poppins',sans-serif}
.wk-top .email-line:hover{color:var(--iris)}

/* --- pages 4 and 5: the vendor panel ---
   One chapter across two frames: a tablet hero with the name burnt into the
   foot of it, the overview, the two columns of role and contribution, then
   three screens of the panel each introduced by a short note. */
.wk-hero{position:relative;overflow:hidden;aspect-ratio:1121/540;border-radius:calc(40 * var(--px));margin-top:var(--gap-figure)}
/* The frame lays the photograph in larger than the window and higher than it,
   so the tablet sits where it does; these are the frame's own offsets. */
.wk-hero>img{position:absolute;left:calc(-.8 * var(--px));top:calc(-35.1 * var(--px));width:calc(1122 * var(--px));height:calc(748 * var(--px));max-width:none;object-fit:cover}
.wk-hero-scrim{position:absolute;left:0;top:calc(166 * var(--px));width:100%;height:calc(374 * var(--px));background:linear-gradient(180deg,rgba(0,0,0,0) 0%,#000 95%);pointer-events:none}
.wk-hero-cap{position:absolute;left:0;right:0;top:calc(452 * var(--px));text-align:center;color:#fff;font-size:max(15px,calc(20 * var(--px)));font-weight:600;line-height:1.6}

/* the overview sits tighter and darker than the notes that follow */
.wk-over{margin-top:var(--gap-section)}
.wk-over h3{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:var(--iris)}
.wk-over p{margin-top:8px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--ink)}

/* a short note introducing a screen */
.wk-note{margin-top:var(--gap-section)}
.wk-note h3{font-size:var(--fs-label);font-weight:600;line-height:var(--lh-label);color:var(--iris)}
.wk-note p{font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

/* the vendor chapter's columns are 340 and 697, not the 482/561 used earlier */
.wk-two--vendor{grid-template-columns:minmax(0,340fr) minmax(0,697fr);gap:clamp(30px,calc(84 * var(--px)),84px)}
.wk-two .wk-sub p{margin-top:20px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--body)}

/* a screen of the panel, rimmed the way the frame rims it */
.wk-shot{margin:var(--gap-figure) 0 0;border:max(3px,calc(5 * var(--px))) solid rgba(255,255,255,.4);border-radius:calc(20 * var(--px));overflow:hidden;line-height:0;box-shadow:0 18px 46px -26px rgba(32,0,60,.34)}
.wk-shot img{display:block;width:100%;height:auto}
.wk-shot--white{border-color:#fff;border-width:max(3px,calc(6 * var(--px)))}
.wk-shot--veil{border-color:rgba(255,255,255,.7)}
@media(max-width:700px){
.wk-two--vendor{grid-template-columns:1fr}
.wk-hero{aspect-ratio:1121/620}
}

/* ===================================================================
   Spemai — selected work 02
   Same column and the same --px scaling as qlub, in the product's own
   cream-to-green. The frames are 1240 wide on a 1120 content column.
   =================================================================== */
.sp-hero{position:relative;box-sizing:border-box;aspect-ratio:1120/574;border:max(2px,calc(4 * var(--px))) solid #fff;border-radius:calc(40 * var(--px));overflow:hidden;background:linear-gradient(154.21deg,#fffef5 23.775%,#23a078 275.74%)}
/* Light rays, drawn far outside the panel and cropped by it. The frame gives
   this as four insets, but an image does not stretch to them the way a box
   does, so the same figures are carried into its width and height. */
.sp-hero-rays{position:absolute;top:calc(-62.88% - 9.03 * var(--px));left:calc(-24.82% - 5.99 * var(--px));width:calc(149.57% + 11.97 * var(--px));height:calc(222.76% + 17.82 * var(--px));max-width:none;pointer-events:none}
.sp-hero-in{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:calc(652 * var(--px));display:flex;flex-direction:column;align-items:center;gap:calc(22 * var(--px));text-align:center}
.sp-kicker{font-size:max(13px,calc(16 * var(--px)));font-weight:600;line-height:2;color:var(--jade-ink);white-space:nowrap}
.sp-wordmark{display:block;width:calc(266 * var(--px));height:auto}
.sp-hero-sub{font-size:max(12px,calc(14 * var(--px)));font-weight:500;line-height:1.5;color:var(--jade-deep)}

/* The statement that opens the case study. */
.sp-lead{margin-top:var(--gap-section);max-width:calc(991 * var(--px));font-size:clamp(22px,2.6vw,30px);font-weight:600;line-height:1.375;color:var(--jade-ink);text-wrap:pretty}
.sp-lead b{font-weight:600;color:var(--jade)}

/* My Role / Responsibilities / Platform, on the frame's own three columns. */
/* The frame holds these apart by capping each paragraph well inside its
   track; at the shared reading size they fill it, so the columns take a
   gutter instead and keep the frame's uneven rhythm. */
.sp-facts{display:grid;grid-template-columns:minmax(0,415fr) minmax(0,366fr) minmax(0,339fr);column-gap:clamp(18px,calc(40 * var(--px)),40px);margin-top:var(--gap-section)}
.sp-facts h3{font-size:var(--fs-label);font-weight:500;line-height:var(--lh-label);color:var(--jade-label)}
.sp-facts p{margin-top:10px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--jade-body)}

/* The three screens, on their cream-to-green ground. */
.sp-stage{margin-top:var(--gap-section);border:max(4px,calc(10 * var(--px))) solid rgba(255,255,255,.5);border-radius:calc(40 * var(--px));overflow:hidden;line-height:0}
.sp-stage-in{position:relative;container-type:inline-size;--px:calc(100cqw / 1120);aspect-ratio:1120/608;background:linear-gradient(180deg,#fffef5 0%,#c7e7d5 100%)}
/* The frame tiles 50px rounded squares at two very low alphas behind the
   phones; one tile at their average reads the same once it is faded. */
.sp-tiles{position:absolute;left:calc(-10 * var(--px));top:calc(-78 * var(--px));right:calc(-70 * var(--px));bottom:calc(-70 * var(--px));opacity:.3;background-repeat:repeat;background-size:calc(70 * var(--px)) calc(70 * var(--px));background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='70' height='70'%3E%3Crect width='50' height='50' rx='9' fill='rgba(20,73,54,0.045)'/%3E%3C/svg%3E")}
.sp-phone{position:absolute;box-sizing:border-box;border:max(3px,calc(10 * var(--px))) solid rgba(255,255,255,.5);border-radius:calc(20 * var(--px));overflow:hidden}
.sp-phone img{display:block;width:100%;height:100%;object-fit:cover}
.sp-phone--home{left:calc(92 * var(--px));top:calc(97 * var(--px));width:calc(274 * var(--px));height:calc(743 * var(--px))}
.sp-phone--mid{left:calc(422 * var(--px));top:calc(66 * var(--px));width:calc(274 * var(--px));height:calc(594 * var(--px));border-width:max(3px,calc(9 * var(--px)))}
.sp-phone--pay{left:calc(752 * var(--px));top:calc(97 * var(--px));width:calc(275 * var(--px));height:calc(595 * var(--px))}
/* the frosted patch over the account number */
.sp-redact{position:absolute;left:calc(190 * var(--px));top:calc(142 * var(--px));width:calc(80 * var(--px));height:calc(25 * var(--px));border-radius:calc(10 * var(--px));background:rgba(255,255,255,.32);backdrop-filter:blur(3.5px);-webkit-backdrop-filter:blur(3.5px)}

@media(max-width:700px){
.sp-facts{grid-template-columns:1fr;gap:22px}
}

/* --- Spemai page 2: the product areas --- */
.sp-block{margin-top:var(--gap-chapter)}
.sp-h2{font-size:var(--fs-h2);font-weight:600;line-height:var(--lh-h2);color:#000}
.sp-h2-sub{font-size:var(--fs-label);font-weight:600;line-height:var(--lh-label);color:#00be9c}
.sp-p{margin-top:16px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:#5a5a5a}

/* The banner: a gradient card with a swirl drawn far outside it and the
   coins bursting past its top edge. */
.sp-banner{position:relative;container-type:inline-size;--px:calc(100cqw / 1120);overflow:hidden;border-radius:calc(12 * var(--px));min-height:calc(188 * var(--px));display:flex;align-items:center;margin-top:var(--gap-section);background:linear-gradient(134.76deg,rgba(35,160,120,.28) 0%,rgba(210,193,84,.02) 100%)}
.sp-banner-swirl{position:absolute;left:calc(50% + 456.5 * var(--px));top:calc(50% + 31 * var(--px));width:calc(2047 * var(--px));height:calc(2138 * var(--px));max-width:none;transform:translate(-50%,-50%);pointer-events:none}
.sp-banner-art{position:absolute;left:calc(831 * var(--px));top:calc(-9 * var(--px));width:calc(348 * var(--px));height:calc(244 * var(--px));max-width:none;object-fit:cover;filter:drop-shadow(0 calc(21 * var(--px)) calc(21 * var(--px)) rgba(255,255,255,.26))}
.sp-banner-in{position:relative;z-index:1;padding:calc(30 * var(--px)) calc(40 * var(--px));max-width:calc(800 * var(--px))}
.sp-banner-in h3{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#00130c}
.sp-banner-in p{margin-top:10px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:#106042}

/* A note above a row of screens. */
.sp-note{margin-top:var(--gap-section);max-width:calc(987 * var(--px))}
.sp-note h3{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#000}
.sp-note p{margin-top:8px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:#5a5a5a}

/* Four screens across the column, on the frame's 256 + 32 rhythm. */
.sp-screens{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:calc(32 * var(--px));margin-top:var(--gap-figure)}
.sp-screen{border:1px solid rgba(192,192,192,.22);border-radius:calc(30 * var(--px));overflow:hidden;line-height:0;background:#fff}
.sp-screen img{display:block;width:100%;height:auto}

/* The pale note that closes the chapter. */
.sp-card{margin-top:var(--gap-section);padding:calc(30 * var(--px));border:1px solid #d7fff6;border-radius:calc(12 * var(--px));background:linear-gradient(106.76deg,#caffec 46.519%,#fffdf0 52.007%,#f4fffb 97.801%)}
.sp-card p:first-child{font-size:var(--fs-label);font-weight:500;line-height:var(--lh-label);color:var(--jade-label)}
.sp-card p:last-child{margin-top:10px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:var(--jade-body)}

@media(max-width:700px){
.sp-screens{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
.sp-banner{min-height:0}
.sp-banner-in{padding:22px 20px}
.sp-banner-art{width:150px;height:105px;left:auto;right:-14px;top:-10px}
.sp-card{padding:22px}
}

/* --- Spemai page 3: the financial tools and the AI work --- */
/* The payment-link row is rimmed in the frame's own grey and its screens sit
   a touch tighter than the getting-started row. */
.sp-screens--tight{gap:calc(25 * var(--px))}
.sp-screens--tight .sp-screen{border-color:#f0eef1}
/* The last of the four is a taller capture shown from its top edge, so it is
   cropped rather than fitted. */
.sp-screen--crop{position:relative;aspect-ratio:261/568;overflow:hidden}
.sp-screen--crop img{position:absolute;left:-.17%;top:0;width:100.34%;height:129.23%;max-width:none;object-fit:cover}
/* A wide capture of the web app. */
.sp-web{margin-top:var(--gap-figure);border-radius:calc(20 * var(--px));overflow:hidden;line-height:0;box-shadow:0 20px 50px -30px rgba(0,40,28,.4)}
.sp-web img{display:block;width:100%;height:auto}

/* --- Spemai page 4: the landing page --- */
.sp-two{display:grid;grid-template-columns:minmax(0,455fr) minmax(0,453fr);gap:clamp(28px,calc(187 * var(--px)),187px);margin-top:var(--gap-section)}
.sp-two h3{font-size:var(--fs-h3);font-weight:600;line-height:var(--lh-h3);color:#000}
.sp-two p{margin-top:14px;font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);color:#5a5a5a}

/* The landing page laid on a lime-to-green ground: the same capture twice,
   the long one in front and a narrower one behind it on the right, both far
   taller than the window that crops them. The frame draws this 1095 wide. */
.sp-land{position:relative;container-type:inline-size;--px:calc(100cqw / 1095);box-sizing:border-box;aspect-ratio:1095/775;margin-top:var(--gap-section);border:max(2px,calc(4 * var(--px))) solid #fff;border-radius:calc(40 * var(--px));overflow:hidden;background:linear-gradient(180deg,#feffdf 0%,#71aa61 100%)}
/* The frame gives these their full page height and lets the panel crop them.
   Laying them out that tall here makes a layer thousands of pixels deep that
   the browser gives up on rasterising, so each one is instead the size of the
   window that shows it and object-position takes the same slice. */
.sp-land img{position:absolute;max-width:none;object-fit:cover;border-radius:calc(20 * var(--px))}
.sp-land-back{left:calc(680 * var(--px));top:0;width:calc(362 * var(--px));height:calc(775 * var(--px));object-position:left 26.73%}
.sp-land-front{left:calc(48 * var(--px));top:calc(48 * var(--px));width:calc(736 * var(--px));height:calc(727 * var(--px));object-position:left top;box-shadow:0 4px calc(114 * var(--px)) rgba(0,0,0,.07)}


@media(max-width:700px){
.sp-two{grid-template-columns:1fr;gap:24px}
.sp-land{aspect-ratio:1095/900}
}


/* --- the foot of a case study ---
   Below the case study the page returns to the site's closing sections, the
   CTA and the footer. Those sit on the site's ambient layer -- a grey grain
   over white -- which met the case study's wash at a hard line and turned the
   foot of the page grey. On these pages the closing sections carry the tail of
   that same wash instead: the grain goes, and the drifting blooms take the
   case study's violet so nothing warm cuts across it. */
/* The wash used to be painted on the case study section, which is opaque and
   stops above the closing sections -- so wherever it stopped there was a step.
   It is painted on the document instead, and the case study is transparent, so
   one surface runs from the header through to the footer. */
/* Each case study's ground follows its own mark: qlub's is purple, Spemai's
   is green. The wash, the drifting blooms and the hairlines all come from
   these, so a page is one colour family from the header to the footer. */
body.wk-doc{
  --pad:24px;
  --doc-wash:#faf4ff;
  --doc-tail:#fdfaff;
  --doc-bloom:rgba(125,0,212,.055);
  --doc-line:#efe8f4;
  --doc-tick:#d8cbe2;
  --doc-accent:var(--iris);
  background:radial-gradient(120% 58% at 50% 24%,#fff 3%,var(--doc-wash) 48%,var(--doc-tail) 100%);
}
body.sp-doc{
  --doc-wash:#f0faf5;
  --doc-tail:#fafefb;
  --doc-bloom:rgba(35,160,120,.06);
  --doc-line:#e2f1e9;
  --doc-tick:#c4dccf;
  --doc-accent:var(--jade);
}
body.wk-doc .wk-page{background:none}
body.wk-doc .ambient .tex{display:none}
body.wk-doc .ambient .g{background:radial-gradient(circle,var(--doc-bloom) 0%,transparent 70%)}
body.wk-doc .sect-rule{background:var(--doc-line)}
body.wk-doc .sect-rule i::before,body.wk-doc .sect-rule i::after{background:var(--doc-tick)}
body.wk-doc footer .rule{border-top-color:var(--doc-line)}
body.wk-doc::before,body.wk-doc::after{background:var(--doc-line)}
/* On this column the site's own hairlines already fall 24px outside the text,
   so they only need the case study's colour, not a new position. */
/* and the things that light up on hover follow the same mark */
body.wk-doc .wk-top .cs-back:hover,body.wk-doc .wk-top .email-line:hover{color:var(--doc-accent)}
body.wk-doc footer .socials a:hover svg{stroke:var(--doc-accent)}


/* ===================================================================
   Motion on scroll
   The site already reveals a block when it comes into view: .rv fades and
   lifts it, and js/page.js adds .in. What follows builds on that so the
   composed pieces -- a grid of tiles, a row of screens, the phones on a
   stage -- arrive one after another rather than all at once.

   A container marked .rv-group does not fade itself; it only carries the
   .in that starts its children, so nothing animates behind an invisible
   parent.
   =================================================================== */
.rv-group.rv{opacity:1;transform:none;filter:none;transition:none}

/* the shape every revealed piece shares */
.wk-bento.rv .wk-card,
.wk-stage-fixed.rv .wk-gcard,
.wk-impact.rv .wk-impact-cell,
.sp-screens.rv .sp-screen,
.sp-facts.rv > div,
.sp-two.rv > div{
  opacity:0;transform:translateY(24px) scale(.985);
  transition:opacity .8s var(--ease),transform .9s var(--ease);
}
.wk-bento.rv.in .wk-card,
.wk-stage-fixed.rv.in .wk-gcard,
.wk-impact.rv.in .wk-impact-cell,
.sp-screens.rv.in .sp-screen,
.sp-facts.rv.in > div,
.sp-two.rv.in > div{opacity:1;transform:none}

/* the bento sweeps across its three columns and down each one */
.wk-bento.rv.in .wk-bento-col:nth-child(1) .wk-card:nth-child(1){transition-delay:.04s}
.wk-bento.rv.in .wk-bento-col:nth-child(2) .wk-card:nth-child(1){transition-delay:.10s}
.wk-bento.rv.in .wk-bento-col:nth-child(3) .wk-card:nth-child(1){transition-delay:.16s}
.wk-bento.rv.in .wk-bento-col:nth-child(1) .wk-card:nth-child(2){transition-delay:.18s}
.wk-bento.rv.in .wk-bento-col:nth-child(2) .wk-card:nth-child(2){transition-delay:.24s}
.wk-bento.rv.in .wk-bento-col:nth-child(3) .wk-card:nth-child(2){transition-delay:.30s}
.wk-bento.rv.in .wk-bento-col:nth-child(1) .wk-card:nth-child(3){transition-delay:.32s}

/* rows that simply run left to right */
.sp-screens.rv.in .sp-screen:nth-child(1),.sp-facts.rv.in>div:nth-child(1),.sp-two.rv.in>div:nth-child(1){transition-delay:.04s}
.sp-screens.rv.in .sp-screen:nth-child(2),.sp-facts.rv.in>div:nth-child(2),.sp-two.rv.in>div:nth-child(2){transition-delay:.14s}
.sp-screens.rv.in .sp-screen:nth-child(3),.sp-facts.rv.in>div:nth-child(3){transition-delay:.24s}
.sp-screens.rv.in .sp-screen:nth-child(4){transition-delay:.34s}
.wk-impact.rv.in .wk-impact-cell:nth-child(2){transition-delay:.12s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(1){transition-delay:.04s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(2){transition-delay:.12s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(3){transition-delay:.20s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(4){transition-delay:.28s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(5){transition-delay:.36s}
.wk-stage-fixed.rv.in .wk-gcard:nth-child(6){transition-delay:.44s}

/* The phones settle onto their stage. Each keeps its resting transform in
   --rest, so the lift can be laid in front of it without losing the tilt. */
.wk-stage.rv .wk-phone{opacity:0;transform:translateY(38px) var(--rest);transition:opacity .85s var(--ease),transform 1.1s var(--ease)}
.wk-stage.rv.in .wk-phone{opacity:1;transform:var(--rest)}
.wk-stage.rv.in .wk-phone--mid{transition-delay:.05s}
.wk-stage.rv.in .wk-phone--left{transition-delay:.19s}
.wk-stage.rv.in .wk-phone--right{transition-delay:.31s}

.sp-stage.rv .sp-phone{opacity:0;transform:translateY(38px);transition:opacity .85s var(--ease),transform 1.1s var(--ease)}
.sp-stage.rv.in .sp-phone{opacity:1;transform:none}
.sp-stage.rv.in .sp-phone--mid{transition-delay:.05s}
.sp-stage.rv.in .sp-phone--home{transition-delay:.19s}
.sp-stage.rv.in .sp-phone--pay{transition-delay:.31s}
.sp-stage.rv .sp-redact{opacity:0;transition:opacity .6s var(--ease) .5s}
.sp-stage.rv.in .sp-redact{opacity:1}

/* The hero's three lines arrive under its wordmark. */
.sp-hero.rv .sp-kicker,.sp-hero.rv .sp-wordmark,.sp-hero.rv .sp-hero-sub{opacity:0;transform:translateY(16px);transition:opacity .8s var(--ease),transform .9s var(--ease)}
.sp-hero.rv.in .sp-kicker,.sp-hero.rv.in .sp-wordmark,.sp-hero.rv.in .sp-hero-sub{opacity:1;transform:none}
.sp-hero.rv.in .sp-kicker{transition-delay:.10s}
.sp-hero.rv.in .sp-wordmark{transition-delay:.20s}
.sp-hero.rv.in .sp-hero-sub{transition-delay:.32s}

/* The coins are already mid-burst, so they come in with a little scale. */
.sp-banner.rv .sp-banner-art{opacity:0;transform:translateY(-10px) scale(.9);transition:opacity .9s var(--ease) .12s,transform 1.1s var(--ease) .12s}
.sp-banner.rv.in .sp-banner-art{opacity:1;transform:none}
.sp-banner.rv .sp-banner-in{opacity:0;transform:translateY(16px);transition:opacity .8s var(--ease),transform .9s var(--ease)}
.sp-banner.rv.in .sp-banner-in{opacity:1;transform:none}

/* The landing page: the panel behind arrives first, then the one in front. */
.sp-land.rv .sp-land-back,.sp-land.rv .sp-land-front{opacity:0;transform:translateY(30px);transition:opacity .9s var(--ease),transform 1.05s var(--ease)}
.sp-land.rv.in .sp-land-back,.sp-land.rv.in .sp-land-front{opacity:1;transform:none}
.sp-land.rv.in .sp-land-back{transition-delay:.06s}
.sp-land.rv.in .sp-land-front{transition-delay:.20s}

@media(prefers-reduced-motion:reduce){
/* nothing moves; the pieces are simply there */
.wk-bento.rv .wk-card,.wk-stage-fixed.rv .wk-gcard,.wk-impact.rv .wk-impact-cell,
.sp-screens.rv .sp-screen,.sp-facts.rv>div,.sp-two.rv>div,
.wk-stage.rv .wk-phone,.sp-stage.rv .sp-phone,.sp-stage.rv .sp-redact,
.sp-hero.rv .sp-kicker,.sp-hero.rv .sp-wordmark,.sp-hero.rv .sp-hero-sub,
.sp-banner.rv .sp-banner-art,.sp-banner.rv .sp-banner-in,
.sp-land.rv .sp-land-back,.sp-land.rv .sp-land-front{
  opacity:1;transform:none;transition:none;
}
.wk-stage.rv .wk-phone{transform:var(--rest)}
}
