/* ============================================================
   Case study page (/work/<slug>/)

   Only what the case template adds. The industry card, the stack marquee,
   the moon CTA, the buttons, the eyebrow and the reveal animation all come
   from global.css and service.css, which is why this file is short.
   ============================================================ */

/* service.css carries the industry card and the stack rail; the case page
   loads only global.css plus this file, so pull those in rather than
   copying them and having two definitions drift apart. */
@import url('service.css');

.ap-case{display:block}

.ap-case-section{position:relative; padding:clamp(70px,10vh,120px) 0}

/* section headings share one rhythm across the page */
.ap-case-head{max-width:760px; margin-bottom:clamp(34px,5vh,56px)}
.ap-case-head .ap-display{font-size:clamp(30px,4.2vw,58px); line-height:1.02; margin-top:14px}
.ap-case-lead{
  margin:18px 0 0; font-size:clamp(15px,1.15vw,17.5px); font-weight:300;
  line-height:1.62; color:var(--muted); max-width:62ch; text-wrap:pretty;
}

/* ---------- hero ---------- */
/* the header is fixed and the breadcrumb is the first thing in the page, so
   the hero has to clear it rather than start at the top of the document */
.ap-case-hero{position:relative; padding:clamp(104px,14vh,150px) 0 clamp(50px,7vh,84px); overflow-x:clip}
.ap-case-crumbs{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  font-family:'Space Mono',monospace; font-size:11px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted); margin-bottom:clamp(26px,4vh,44px);
}
.ap-case-crumbs a{color:var(--muted); text-decoration:none; transition:color .25s ease}
.ap-case-crumbs a:hover{color:var(--orange)}
.ap-case-crumbs span{color:var(--paper)}
.ap-case-crumbs i{display:inline-flex; font-size:9px; opacity:.5}

/* 60/40. The columns used to be even, which left the headline about nine
   characters wide per line and every case ran to four or five of them. */
.ap-case-hero-grid{
  display:grid; grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);
  gap:clamp(28px,4vw,60px); align-items:center;
}
.ap-case-hero-copy .ap-display{
  /* smaller too: the headline is the longest string on the page and it was
     set at the same size as a two-word section title */
  font-size:clamp(32px,3.9vw,58px); line-height:1.02; margin-top:16px;
}
.ap-case-hero-copy .ap-lead{margin:22px 0 0; max-width:52ch}
.ap-case-hero-copy .ap-buttons{
  /* .ap-buttons centres its row for the CTA bands; in a hero column it
     starts where the headline starts */
  margin-top:30px; justify-content:flex-start;
}

/* The two mockups at rest. The web-design hero animates them on a parallax
   rig tied to that page's scroll; here they are furniture, so they just sit
   at a fixed tilt and cost nothing per frame. */
.ap-case-hero-art{
  position:relative; aspect-ratio:1/.78; min-height:300px;
  /* min-height plus an aspect ratio makes the BOX solve for width, which on a
     phone came out wider than the screen: the cap has to be explicit. */
  max-width:100%;
}
/* The mockups come from service.css whole. It places them against the
   viewport for the web-design hero, which is the one thing that cannot
   carry over: here they live inside a grid cell. */
/* The art column is now 40% rather than half, so the mockups reach past it
   on the right to keep the size they had. The section clips the overflow. */
@media (min-width:1101px){
  /* max-width caps it to the cell, which is exactly what has to give here */
  .ap-case-hero-art{width:128%; max-width:none; margin-right:-28%}
}
.ap-case-hero-art .ap-mock{filter:drop-shadow(0 40px 70px rgba(0,0,0,.6))}
/* The device frame is the largest thing on a case hero, so it is the page's
   Largest Contentful Paint, and as a scroll reveal it stayed at opacity 0 until
   global.js had loaded and the observer had fired: 3.4s on a throttled phone,
   1.4s after the title. Now a CSS animation that starts with the first style
   pass and waits for no script. Equal specificity to
   .ap-rv.is-in and later in the cascade, so the reveal does not replay. */
/* Rise only, no fade and no delay, like the titles: under a throttled CPU the
   fade's first visible frame landed close to a second after the image had
   arrived, and the LCP is taken from that frame. */
.ap-case-hero-art.ap-rv{opacity:1; transform:none; animation:apCaseArtIn .9s cubic-bezier(.19,.82,.22,1) both}
@keyframes apCaseArtIn{
  from{transform:translateY(26px)}
  to{transform:none}
}
@media (prefers-reduced-motion:reduce){
  .ap-case-hero-art.ap-rv{animation:none}
}
.ap-case-hero-art .ap-mock--desktop{left:0; top:3%; width:86%}
.ap-case-hero-art .ap-mock--phone{left:auto; right:0; top:auto; bottom:0; width:23%}
/* alone, the desktop frame takes the room the phone was leaving it */
.ap-case-hero-art.is-solo{aspect-ratio:1/.66}
.ap-case-hero-art.is-solo .ap-mock--desktop{top:0; width:100%}


/* ---------- the numbers, straight off the hero ----------
   Full bleed and orange: the one place on the page that inverts, so the
   figures read before anything else on the way down. */
.ap-case-band{
  background:var(--orange); color:#0a0503;
  padding:clamp(20px,3vh,30px) 0;
  border-top:1px solid rgba(0,0,0,.18); border-bottom:1px solid rgba(0,0,0,.18);
}
/* One row, always. Four figures with long labels used to wrap and leave a
   single number stranded on a second line, which reads as a mistake. The
   row never wraps above the phone breakpoint; the cells shrink and their
   labels take a second line instead, which is what a label is for. */
.ap-case-band-in{
  display:flex; align-items:center; justify-content:center;
  flex-wrap:nowrap; gap:clamp(14px,2.4vw,44px);
}
.ap-case-num{
  text-align:center; padding-inline:clamp(8px,1.4vw,26px);
  border-left:1px solid rgba(0,0,0,.22);
  min-width:0; flex:0 1 auto;
}
/* The numeral shrinks to fit and NEVER breaks: a number split over two
   lines stops reading as a number ("24/7" broke at the slash). The label
   underneath may still wrap, which is what the clamp leaves room for. */
.ap-case-num b{white-space:nowrap}
.ap-case-num:first-child{border-left:0}
.ap-case-num b{
  display:block; font-family:'Anton',sans-serif; font-weight:400;
  font-size:clamp(24px,3.9vw,58px); line-height:1; letter-spacing:.005em;
  font-variant-numeric:tabular-nums;
}
.ap-case-num span{
  display:block; margin-top:7px; font-size:clamp(12px,1.05vw,14.5px); font-weight:500;
  line-height:1.3; color:rgba(10,5,3,.78); text-wrap:balance;
}
.ap-case-band-note{
  margin:0; margin-left:auto; max-width:26ch;
  /* it sits on the orange band, where 10.5px of thin mono at 62% opacity
     was not readable: bigger, heavier and nearly opaque */
  font-family:'Space Mono',monospace; font-size:12.5px; font-weight:700; line-height:1.5;
  letter-spacing:.02em; color:rgba(10,5,3,.9);
}

/* ---------- the film ----------
   A poster and a play button until somebody asks for the video. The frame
   holds the aspect the data declares, so a square or vertical cut does not
   have to be letterboxed into a 16:9 hole. */
.ap-case-film{padding-top:clamp(40px,6vh,70px)}
.ap-case-film-frame{
  position:relative; margin-top:clamp(20px,3vh,32px);
  aspect-ratio:var(--ratio,16 / 9); overflow:hidden;
  border:1px solid var(--line); border-radius:18px; background:#07080c;
  box-shadow:0 40px 90px -50px rgba(0,0,0,.95);
}
.ap-case-film-poster,.ap-case-film-frame iframe{
  position:absolute; inset:0; width:100%; height:100%; display:block; border:0;
}
.ap-case-film-poster{object-fit:cover; transition:scale .6s cubic-bezier(.2,.7,.3,1), opacity .4s ease}
/* a hosted loop fills the same frame, with nothing over it: no scrim, no
   play control, nothing to press */
.ap-case-film-loop{width:100%; height:100%; object-fit:cover; display:block}
.ap-case-film-frame.is-loop{cursor:default}
.ap-case-film-frame.is-loop::after{display:none}
.ap-case-film-frame::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(3,3,5,.25),rgba(3,3,5,.55));
  transition:opacity .4s ease;
}
.ap-case-film-frame.is-playing::after{opacity:0}

.ap-case-film-play{
  position:absolute; inset:0; z-index:2; width:100%; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:18px;
  border:0; background:none; color:var(--paper); font-family:inherit;
}
.ap-case-film-frame:hover .ap-case-film-poster{scale:1.03}
.ap-case-film-dot{
  width:clamp(64px,7vw,92px); aspect-ratio:1; border-radius:50%; flex:none;
  background:var(--orange); position:relative;
  box-shadow:0 0 0 1px rgba(255,160,110,.5) inset, 0 0 40px 4px rgba(255,90,20,.45);
  transition:scale .3s ease, box-shadow .3s ease;
}
/* the triangle is drawn, not a glyph: a glyph sits off-centre in a circle
   at every size and has to be nudged per font */
.ap-case-film-dot::after{
  content:""; position:absolute; top:50%; left:54%; translate:-50% -50%;
  border-style:solid; border-width:11px 0 11px 18px;
  border-color:transparent transparent transparent #140802;
}
.ap-case-film-play:hover .ap-case-film-dot{scale:1.06; box-shadow:0 0 0 1px rgba(255,180,140,.6) inset, 0 0 56px 8px rgba(255,90,20,.6)}
.ap-case-film-play:focus-visible{outline:2px solid var(--orange); outline-offset:-6px}
.ap-case-film-label{text-align:left}
.ap-case-film-label b{
  display:block; font-family:'Anton',sans-serif; font-weight:400;
  text-transform:uppercase; letter-spacing:.02em; font-size:clamp(20px,2.2vw,30px);
}
.ap-case-film-label span{
  display:block; margin-top:4px; font-family:'Space Mono',monospace;
  font-size:11px; letter-spacing:.18em; color:var(--muted);
}
.ap-case-film-cap{
  margin:16px 0 0; font-family:'Space Mono',monospace; font-size:11.5px;
  letter-spacing:.1em; color:var(--muted);
}
@media (max-width:640px){
  .ap-case-film-play{flex-direction:column; gap:14px}
  .ap-case-film-label{text-align:center}
}

/* ---------- fact bar ---------- */
.ap-case-facts{border-top:1px solid var(--line); border-bottom:1px solid var(--line)}
.ap-case-facts-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  margin:0;
}
/* right padding too: a long services list otherwise runs into the next cell's rule */
.ap-case-facts-grid > div{padding:26px 26px 26px 26px; border-left:1px solid var(--line)}
.ap-case-facts-grid > div:first-child{padding-left:0; border-left:0}
.ap-case-facts-grid dt{
  font-family:'Space Mono',monospace; font-size:10.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--muted); margin-bottom:9px;
}
.ap-case-facts-grid dd{margin:0; font-size:15.5px; font-weight:400; color:var(--paper); line-height:1.45}
.ap-case-facts-grid dd a{color:var(--paper); text-decoration:none; border-bottom:1px solid rgba(255,90,20,.45)}
.ap-case-facts-grid dd a:hover{color:var(--orange)}

/* ---------- the challenge ---------- */
.ap-case-note{
  max-width:74ch; margin:0 0 clamp(34px,5vh,52px);
  font-size:16px; font-weight:300; line-height:1.68; color:var(--muted);
  border-left:2px solid rgba(255,90,20,.5); padding-left:22px; text-wrap:pretty;
}
.ap-case-probs{display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:18px}
.ap-case-prob{
  position:relative; padding:26px 24px 24px;
  border:1px solid var(--line); border-radius:14px;
  background:linear-gradient(180deg,rgba(18,20,27,.85),rgba(8,9,13,.85));
  transition:border-color .35s ease, translate .35s ease;
}
.ap-case-prob:hover{border-color:rgba(255,90,20,.42); translate:0 -4px}
.ap-case-prob-n{
  display:block; font-family:'Space Mono',monospace; font-size:11px;
  letter-spacing:.2em; color:var(--orange); margin-bottom:14px;
}
.ap-case-prob h3{margin:0 0 9px; font-size:18px; font-weight:500; color:var(--paper); line-height:1.3}
.ap-case-prob p{margin:0; font-size:14.5px; font-weight:300; line-height:1.6; color:var(--muted); text-wrap:pretty}

/* ---------- the solution ---------- */
/* The numerals hang outside the shell by design. On a phone the shell is
   nearly the viewport, so the overhang became a horizontal scrollbar:
   clipped at the SECTION, which is full width, the overhang still shows on
   a desktop and simply stops at the screen edge on a phone. */
.ap-case-solution{overflow-x:clip}
/* The numerals hang off the corners now, so the blocks need room or the
   02 of one lands on the artwork of the one above it. */
.ap-case-delivs{display:flex; flex-direction:column; gap:clamp(64px,11vh,140px)}
.ap-case-deliv{
  position:relative;
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(24px,3.5vw,56px); align-items:center;
  /* named for the numeral's drift, below; inert where it is unsupported */
  view-timeline:--ap-deliv block;
}
/* Outlined, behind everything, and overlapped by the artwork on purpose: it
   indexes the block without competing with it. It sits on the side the
   image is not, and the image alternates, so the numeral alternates too. */
.ap-case-deliv-n{
  position:absolute; top:-.44em; right:-.45em; z-index:0;
  font-family:'Anton',sans-serif; font-size:clamp(110px,14vw,220px); line-height:1;
  letter-spacing:-.02em; color:transparent; user-select:none; pointer-events:none;
  -webkit-text-stroke:1.5px rgba(238,240,246,.3);
}
/* The numeral drifts against its block as the block crosses the viewport,
   which is what gives the index its depth. It is a scroll-driven animation,
   so it costs the scroll thread nothing and needs no script; a browser
   without them simply gets the numeral standing still.

   `translate` rather than `transform`: the numeral is absolutely positioned
   by top/right and nothing else here owns that property. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .ap-case-deliv-n{
      /* longhands on purpose: the `animation` shorthand sets duration to 0s,
         and a scroll-driven animation needs `auto` to span its range */
      animation-name:apDelivDrift;
      animation-duration:auto;
      animation-timing-function:linear;
      animation-fill-mode:both;
      /* the timeline is the BLOCK's pass through the viewport, not the
         numeral's: the numeral hangs above its block and would otherwise
         finish drifting while the block is still being read */
      animation-timeline:--ap-deliv;
      animation-range:entry 0% exit 100%;
    }
    @keyframes apDelivDrift{
      from{translate:0 26%}
      to{translate:0 -26%}
    }
  }
}
.ap-case-deliv:nth-child(even) .ap-case-deliv-n{right:auto; left:-.45em}
.ap-case-deliv-copy{position:relative; z-index:2}
.ap-case-deliv-art{position:relative; z-index:1}
/* alternate sides, the same zigzag as the service rows, without the rail */
.ap-case-deliv:nth-child(even) .ap-case-deliv-copy{order:2}
.ap-case-deliv.is-plain{grid-template-columns:minmax(0,1fr); max-width:760px}
.ap-case-deliv.is-plain .ap-case-deliv-n{right:-.45em; opacity:.8}
.ap-case-deliv-tag{
  display:inline-block; font-family:'Space Mono',monospace; font-size:10.5px;
  letter-spacing:.2em; color:var(--orange); margin-bottom:14px;
}
.ap-case-deliv h3{margin:0 0 12px; font-size:clamp(21px,2.2vw,28px); font-weight:500; line-height:1.18; color:var(--paper)}
.ap-case-deliv p{margin:0; font-size:15.5px; font-weight:300; line-height:1.65; color:var(--muted); max-width:56ch; text-wrap:pretty}
.ap-case-points{margin:20px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:12px}
.ap-case-points li{
  position:relative; padding-left:20px; font-size:14.5px; font-weight:300;
  line-height:1.6; color:var(--muted); max-width:56ch;
}
.ap-case-points li::before{
  content:""; position:absolute; left:0; top:.62em; width:8px; height:1px; background:var(--orange);
}
.ap-case-points b{color:var(--paper); font-weight:500}
.ap-case-deliv-art{
  border:1px solid var(--line); border-radius:16px; overflow:hidden;
  background:#07080c; box-shadow:0 30px 70px -40px rgba(0,0,0,.9);
}
.ap-case-deliv-art img{width:100%; height:100%; max-height:420px; object-fit:cover; display:block}
/* A cutout is not a screenshot: framing a transparent mascot in a bordered
   card and cropping it to the card's height would hide half of it and put
   a box around something drawn to have no box. It gets the space instead,
   whole, over a soft glow of its own colour. */
.ap-case-deliv-art.is-bare{
  border:0; background:none; box-shadow:none; overflow:visible;
  display:grid; place-items:center; position:relative;
}
.ap-case-deliv-art.is-bare::before{
  content:""; position:absolute; inset:8% 12%; border-radius:50%;
  background:radial-gradient(circle at 50% 55%, rgba(60,220,160,.20), rgba(20,120,180,.10) 55%, transparent 72%);
  filter:blur(22px);
}
/* artwork that brings its own light does not want a second source */
.ap-case-deliv-art.is-bare.is-flat::before{display:none}
.ap-case-deliv-art.is-bare img,
.ap-case-deliv-art.is-bare .ap-case-deliv-loop{
  position:relative; width:auto; max-width:100%;
  height:auto; max-height:clamp(320px,42vh,520px); object-fit:contain;
  filter:drop-shadow(0 30px 45px rgba(0,0,0,.55));
}
/* a video element paints its own background behind a transparent frame in
   some engines, which would put a black slab where the cutout should be */
.ap-case-deliv-loop{display:block; background:transparent}
/* A loop that carries its own background (the DinoCloud logo keeps the white
   it was drawn on) would otherwise sit on the page as a hard rectangle. It
   costs a transparent one nothing. */
.ap-case-deliv-art.is-bare .ap-case-deliv-loop{border-radius:14px}

.ap-case-arch{
  margin:clamp(34px,5vh,56px) 0 0; max-width:74ch;
  font-size:15.5px; font-weight:300; line-height:1.68; color:var(--muted);
  padding:24px 26px; border:1px solid var(--line); border-radius:14px;
  background:rgba(18,20,27,.5);
}
.ap-case-arch span{
  display:block; font-family:'Space Mono',monospace; font-size:10.5px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--paper); margin-bottom:10px;
}

/* ---------- gallery ----------
   A loop with one frame in the middle and its neighbours dimmed at the
   edges. Slides are placed by their DISTANCE from the active one rather
   than by scrolling a track, which is what makes the loop free: there is
   no end to rewind past. JS writes --o (that distance) on each slide. */
.ap-case-gal-head{font-size:clamp(28px,3.6vw,50px); line-height:1.02; margin:14px 0 clamp(28px,4vh,46px)}
/* --gal-min is the flattest frame in the set, so the stage is exactly as
   tall as the tallest one needs and nothing gets cropped to a common
   height. --slide-w is shared so the two numbers cannot drift apart. */
.ap-case-gal-stage{
  --slide-w:min(58vw,820px);
  position:relative; overflow:hidden;
  /* The row can be pushed. pan-y leaves vertical scrolling to the browser,
     so a finger swiping down the page is never caught by the carousel. */
  cursor:grab; touch-action:pan-y;
  height:min(72vh, calc(var(--slide-w) / var(--gal-min,1.78)));
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 13%,#000 87%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 13%,#000 87%,transparent);
}
.ap-case-gal-stage:focus-visible{outline:2px solid var(--orange); outline-offset:4px}
.ap-case-slide{
  position:absolute; top:50%; left:50%; margin:0; width:var(--slide-w);
  /* the active slide sits at --o:0; each step out shifts by 62% of its own
     width and drops a size, so three are in view and the rest park behind */
  translate:calc(-50% + var(--o,0) * 62%) -50%;
  scale:var(--s,1);
  opacity:var(--a,0);
  z-index:var(--z,1);
  transition:translate .55s cubic-bezier(.2,.7,.3,1), scale .55s cubic-bezier(.2,.7,.3,1), opacity .45s ease;
  pointer-events:none;
}
/* only the three in view can be clicked */
.ap-case-slide[data-near]{pointer-events:auto}
.ap-case-slide-btn{
  display:block; width:100%; padding:0; border:0; background:none;
  border-radius:14px; overflow:hidden; cursor:pointer;
}
.ap-case-slide[data-active] .ap-case-slide-btn{cursor:zoom-in}
/* While the pointer is down the slides track it one to one; the easing
   comes back for the snap on release. */
.ap-case-gal-stage.is-dragging{cursor:grabbing}
.ap-case-gal-stage.is-dragging .ap-case-slide{transition:none}
.ap-case-gal-stage.is-dragging .ap-case-slide-btn,
.ap-case-gal-stage.is-dragging .ap-case-slide img{cursor:grabbing}
/* nothing inside the stage is selectable or natively draggable */
.ap-case-gal-stage img{user-select:none; -webkit-user-drag:none}
.ap-case-slide-btn:focus-visible{outline:2px solid var(--orange); outline-offset:4px}
.ap-case-slide img{
  width:100%; display:block;
  /* Its own shape, never a crop: --r is the file's real ratio, measured
     when the case data was written. The tallest frame sets the stage
     height, so this one simply sits inside it. */
  height:auto; aspect-ratio:var(--r,1.78); object-fit:contain;
  max-height:min(72vh, calc(var(--slide-w) / var(--gal-min,1.78)) - 34px);
  border:1px solid var(--line); border-radius:14px; background:#07080c;
  box-shadow:0 40px 80px -50px rgba(0,0,0,.95);
}
.ap-case-slide figcaption{
  margin-top:14px; text-align:center; font-family:'Space Mono',monospace;
  font-size:11px; letter-spacing:.1em; color:var(--muted);
  opacity:0; transition:opacity .4s ease;
}
.ap-case-slide[data-active] figcaption{opacity:1}

.ap-case-gal-nav{
  display:flex; align-items:center; gap:clamp(16px,3vw,30px);
  margin-top:clamp(24px,4vh,40px);
}
.ap-case-gal-arrow{
  width:46px; height:46px; border-radius:50%; flex:none; cursor:pointer;
  display:grid; place-items:center; font-size:16px; line-height:1;
  border:1px solid var(--line); background:none; color:var(--paper); font-family:inherit;
  transition:border-color .25s ease, color .25s ease;
}
.ap-case-gal-arrow:hover{border-color:var(--orange); color:var(--orange)}
.ap-case-gal-bar{position:relative; flex:1 1 auto; height:2px; background:var(--line)}
.ap-case-gal-bar i{
  position:absolute; left:0; top:0; height:100%; width:var(--p,20%);
  background:var(--orange); transition:width .4s ease;
}

/* ---------- lightbox ---------- */
/* display:grid beats the hidden attribute's display:none, so the closed
   state has to be stated: without this the lightbox ships open. */
.ap-case-lb[hidden]{display:none}
.ap-case-lb{
  position:fixed; inset:0; z-index:120;
  display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center;
  gap:clamp(8px,2vw,26px); padding:clamp(48px,6vh,70px) clamp(12px,3vw,40px);
  background:rgba(3,3,5,.94);
}
.ap-case-lb-fig{margin:0; display:grid; justify-items:center; gap:14px; min-width:0}
.ap-case-lb-fig img{
  max-width:100%; max-height:74vh; width:auto; display:block;
  border:1px solid var(--line); border-radius:12px; background:#07080c;
}
.ap-case-lb-fig figcaption{
  font-family:'Space Mono',monospace; font-size:11.5px; letter-spacing:.1em; color:var(--muted);
}
.ap-case-lb-arrow{
  width:52px; height:52px; border-radius:50%; flex:none; cursor:pointer;
  display:grid; place-items:center; font-size:17px;
  border:1px solid var(--line); background:rgba(12,14,19,.8); color:var(--paper); font-family:inherit;
  transition:border-color .25s ease, color .25s ease;
}
.ap-case-lb-arrow:hover{border-color:var(--orange); color:var(--orange)}
.ap-case-lb-close{
  position:absolute; top:clamp(14px,2.4vh,26px); right:clamp(14px,2.4vw,30px);
  width:44px; height:44px; border-radius:50%; cursor:pointer;
  border:1px solid var(--line); background:none; color:var(--paper);
  font-size:26px; line-height:1; font-family:inherit;
}
.ap-case-lb-close:hover{border-color:var(--orange); color:var(--orange)}

/* ---------- results ---------- */
.ap-case-stats{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
  gap:1px; background:var(--line); border:1px solid var(--line);
}
.ap-case-stat{background:#08090d; padding:30px 26px}
.ap-case-stat b{
  display:block; font-family:'Anton',sans-serif; font-weight:400;
  font-size:clamp(44px,5.4vw,76px); line-height:.92; color:var(--orange);
  letter-spacing:.01em; font-variant-numeric:tabular-nums;
}
.ap-case-stat-label{
  display:block; margin-top:14px; font-size:15px; font-weight:400; color:var(--paper);
}
.ap-case-stat-src{
  display:block; margin-top:6px; font-family:'Space Mono',monospace;
  font-size:10.5px; letter-spacing:.12em; color:var(--muted);
}
/* What the case actually shipped. This is the section that has to land,
   so each line is its own panel with a struck check rather than a bullet:
   on a case with no publishable figures it is the only evidence there is,
   and a plain list read as a footnote. */
.ap-case-delivered{
  margin:clamp(26px,4vh,40px) 0 0; padding:0; list-style:none;
  /* Flex, not a grid: a grid leaves the odd one or two of a last row
     hanging on the left against a hole. Wrapped and centred, a full row
     still spans edge to edge (three bases plus two gaps is exactly 100%)
     and the remainder sits in the middle. */
  display:flex; flex-wrap:wrap; justify-content:center; gap:14px;
}
.ap-case-win{flex:0 1 calc((100% - 28px) / 3); min-width:280px}
.ap-case-win{
  position:relative; display:flex; align-items:center; gap:16px;
  /* flex-basis lives in the rule above, next to the list it belongs to */
  padding:18px 22px; border-radius:14px;
  background:linear-gradient(180deg,rgba(18,20,27,.92),rgba(8,9,13,.92));
  font-size:15.5px; font-weight:400; line-height:1.45; color:var(--paper);
  text-wrap:pretty;
}
/* The lit edge. A gradient painted on the border box and punched out in
   the middle with mask-composite, then slid sideways: one element, no
   extra nodes, and it animates a background position rather than a
   shadow, which is the cheap half of that trade. */
.ap-case-win::before{
  content:""; position:absolute; inset:0; border-radius:inherit; padding:1px;
  background:linear-gradient(100deg,
    rgba(255,90,20,.85) 0%, rgba(255,150,80,.35) 14%,
    rgba(238,240,246,.10) 32%, rgba(238,240,246,.08) 68%,
    rgba(255,150,80,.35) 86%, rgba(255,90,20,.85) 100%);
  background-size:280% 100%; background-position:120% 0;
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor; mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite:exclude;
  pointer-events:none;
}
/* Only while it is on screen: the reveal observer adds is-in when the row
   enters and takes it off once it is fully gone, so eight of these are
   never animating behind the rest of the page. */
.ap-case-win.is-in::before{
  animation:apWinEdge 7s linear infinite;
  animation-delay:calc(var(--i,0) * -.9s);
}
@keyframes apWinEdge{ from{background-position:120% 0} to{background-position:-180% 0} }

.ap-case-win-mark{
  flex:none; width:46px; height:46px; border-radius:50%;
  display:grid; place-items:center; color:var(--orange);
  background:radial-gradient(circle at 50% 50%, rgba(255,90,20,.22), rgba(255,90,20,.07) 70%);
  box-shadow:0 0 0 1px rgba(255,90,20,.42) inset, 0 0 22px -3px rgba(255,90,20,.7);
}
.ap-case-win-mark svg{width:23px; height:23px; display:block}

/* The drifting planets, on the right where the copy stops and the sky is
   empty. Their sections have to clip horizontally or a planet hangs off
   the page on a narrow screen, and they step aside entirely on a phone,
   where there is no empty side for them to sit in. Each one drifts on its
   own clock and in its own direction, so the page never pulses. */
.ap-case-challenge,.ap-case-results{overflow-x:clip}
.ap-case-planet{position:absolute; opacity:.85}
.ap-case-planet--side{
  top:clamp(40px,9vh,120px); right:clamp(-30px,-1vw,0px);
  width:clamp(120px,13vw,215px);
  animation:apDriftR 15s ease-in-out infinite;
}
/* Clear of the fact bar's rule above it, and pulled in from the edge so
   it fills the gap the headline leaves rather than hanging off the
   corner. */
.ap-case-planet--top{
  top:clamp(90px,13vh,190px); right:clamp(10px,4vw,110px);
  width:clamp(260px,31vw,520px); opacity:.72;
  animation:apDriftL 21s ease-in-out infinite;
}
@media (max-width:900px){ .ap-case-planet{display:none} }
@media (prefers-reduced-motion:reduce){ .ap-case-planet{animation:none} }

/* ---------- the quote ---------- */
.ap-case-quote-card{
  position:relative; margin:0; max-width:920px; margin-inline:auto;
  padding:clamp(40px,6vw,64px) clamp(28px,4.5vw,64px) clamp(32px,4vw,48px);
  border:1px solid var(--line); border-radius:22px; overflow:hidden;
  background:
    radial-gradient(120% 90% at 10% 0%, rgba(255,90,20,.14), transparent 58%),
    linear-gradient(180deg,#0e0f15,#08090d);
}
/* the mark is the ornament of this block, so it is big and it is behind the
   words rather than a tidy little glyph above them */
.ap-case-quote-mark{
  position:absolute; left:clamp(10px,2vw,28px); top:clamp(4px,1vw,16px);
  font-family:'Anton',sans-serif; font-size:clamp(150px,19vw,250px); line-height:.78;
  color:rgba(255,90,20,.16); user-select:none; pointer-events:none;
}
.ap-case-quote-card blockquote{
  position:relative; margin:0; font-size:clamp(19px,2.1vw,27px); font-weight:300;
  line-height:1.5; color:var(--paper); text-wrap:pretty;
}
.ap-case-quote-card figcaption{
  position:relative; display:flex; align-items:center; gap:16px;
  margin-top:clamp(26px,3.5vh,38px);
}
.ap-case-quote-face{
  width:56px; height:56px; border-radius:50%; flex:none; object-fit:cover;
  border:1px solid rgba(255,90,20,.5);
}
.ap-case-quote-face--ini{
  display:grid; place-items:center;
  background:linear-gradient(150deg,var(--orange),#7d2f0b);
  font-family:'Space Mono',monospace; font-size:17px; color:#120c07; border-color:transparent;
}
.ap-case-quote-card figcaption b{display:block; font-size:16.5px; font-weight:500; color:var(--paper)}
.ap-case-quote-card figcaption span span{display:block; font-size:13.5px; font-weight:300; color:var(--muted)}

/* ---------- more work ---------- */
.ap-case-more-head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:24px; flex-wrap:wrap; margin-bottom:clamp(28px,4vh,44px);
}
.ap-case-more-head .ap-display{font-size:clamp(28px,3.6vw,48px); line-height:1.02; margin-top:14px}
/* the shared work card, three across */
.ap-case-more-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:22px}

/* ---------- responsive ---------- */
@media (max-width:1024px){
  .ap-case-hero-grid{grid-template-columns:minmax(0,1fr); gap:34px}
  .ap-case-hero-art{order:2; aspect-ratio:1/.62; min-height:0}
  .ap-case-facts-grid > div{padding-left:20px; padding-right:20px}
  .ap-case-deliv{grid-template-columns:minmax(0,1fr)}
  .ap-case-deliv:nth-child(even) .ap-case-deliv-copy{order:0}
}
@media (max-width:760px){
  .ap-case-facts-grid > div{padding:20px 0; border-left:0; border-top:1px solid var(--line)}
  .ap-case-facts-grid > div:first-child{border-top:0}
  .ap-case-rail{padding-inline:20px; scroll-snap-type:x proximity}
  .ap-case-rail-in{gap:16px}
  .ap-case-quote-card{border-radius:18px}
}
@media (prefers-reduced-motion:reduce){
  .ap-case-prob,.ap-ind-card{transition:none}
}

/* ---------- responsive, for the blocks this file adds ---------- */
@media (max-width:1024px){
  .ap-case-win{flex-basis:calc((100% - 14px) / 2)}
}
@media (max-width:760px){
  .ap-case-win{flex-basis:100%}
  /* the only place the row is allowed to break: four cells across a phone
     would be four columns of two characters each */
  .ap-case-band-in{flex-wrap:wrap; gap:18px 22px; justify-content:flex-start}
  .ap-case-num{padding-inline:0; border-left:0; text-align:left; min-width:40%; flex:1 1 40%}
  .ap-case-band-note{margin-left:0; max-width:none}
  .ap-case-slide{width:78vw}
  .ap-case-gal-stage{-webkit-mask-image:none; mask-image:none}
  .ap-case-lb{grid-template-columns:minmax(0,1fr); padding-bottom:88px}
  .ap-case-lb-arrow{position:absolute; bottom:18px}
  .ap-case-lb-arrow--prev{left:calc(50% - 64px)}
  .ap-case-lb-arrow--next{right:calc(50% - 64px)}
}
@media (prefers-reduced-motion:reduce){
  .ap-case-slide{transition:none}
  /* the edge keeps its colour, it just stops travelling */
  .ap-case-win.is-in::before{animation:none; background-position:0 0}
}


/* ==========================================================================
   Measurement cards, rendered in place of a deliverable's artwork.
   Taken from the approved standalone build with its page-level resets
   dropped (they belonged to a document, not to a component) and its font
   stack removed so the cards inherit the site's own.
   ========================================================================== */
  .ud-metrics { --green: #33e981; --text: #f3f7f6; --muted: #bac6cb; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; max-width: 960px; margin: auto; color: var(--text); }
  .ud-metrics .ud-card { position: relative; isolation: isolate; overflow: hidden; min-width: 0; display: flex; flex-direction: column; padding: clamp(18px, 4.4cqi, 30px); border: 1px solid #9bafb45c; border-radius: 28px; background: radial-gradient(ellipse at 15% 0%, #71878a45, transparent 60%), linear-gradient(145deg, #29363bf5, #101a1ef5 65%, #283e3bf5); box-shadow: inset 0 1px 1px #ffffff60, inset 0 -1px 1px #ffffff18, 0 14px 35px #00000020; backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); }
  .ud-metrics .ud-card::after { content: ""; position: absolute; z-index: -1; inset: 0; background: linear-gradient(110deg, transparent 20%, #ffffff0c 48%, transparent 70%); transform: translateX(-110%); pointer-events: none; }
  .ud-metrics .ud-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 28px; padding-bottom: 22px; border-bottom: 1px solid #b7c4c52b; }
  .ud-metrics .ud-heading h2 { margin: 0; font-size: clamp(13px, 3.4cqi, 18px); font-weight: 600; letter-spacing: .065em; }
  .ud-metrics .ud-icon { width: 32px; height: 32px; flex-shrink: 0; fill: none; stroke: #d5e0e2; stroke-width: 1.65; stroke-linecap: round; stroke-linejoin: round; }
  .ud-metrics .ud-value { display: flex; align-items: baseline; gap: 9px; font-size: clamp(46px, 13cqi, 76px); font-weight: 650; letter-spacing: -.055em; line-height: 1.08; font-variant-numeric: tabular-nums; }
  .ud-metrics .ud-unit { font-size: .38em; letter-spacing: -.02em; font-weight: 500; }
  .ud-metrics .ud-label { margin: 9px 0 0; color: var(--muted); font-size: clamp(14px, 3.4cqi, 19px); line-height: 1.4; }
  .ud-metrics .ud-change { margin: 25px 0 0; color: var(--green); font-size: clamp(24px, 6cqi, 34px); font-weight: 550; letter-spacing: -.035em; line-height: 1.1; }
  .ud-metrics .ud-detail { margin: 10px 0 0; color: var(--muted); font-size: clamp(13px, 3cqi, 16px); line-height: 1.5; }
  .ud-metrics .ud-chart { display: block; width: 100%; height: clamp(58px, 15cqi, 92px); margin-top: 24px; overflow: visible; }
  .ud-metrics .ud-line { fill: none; stroke: var(--green); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
  .ud-metrics .ud-area { fill: url(#ud-green-fill); }
  .ud-metrics .ud-dot { fill: #e3ffee; stroke: var(--green); stroke-width: 2; filter: drop-shadow(0 0 5px #33e981); }
  .ud-metrics .ud-footer { margin-top: auto; padding-top: 26px; }
  .ud-metrics .ud-track { height: 15px; border-radius: 99px; background: #ffffff0d; overflow: hidden; }
  .ud-metrics .ud-progress { height: 100%; border-radius: inherit; background: linear-gradient(90deg, #29c56c, #44f292); box-shadow: 0 0 18px #33e98155; transform-origin: left; }
  .ud-metrics .ud-weight { gap: 10px; flex-wrap: nowrap; font-size: clamp(19px, 6.6cqi, 38px); padding-top: 13px; padding-bottom: 13px; letter-spacing: -.04em; }
  .ud-metrics .ud-weight span { white-space: nowrap; }
  .ud-metrics .ud-weight .ud-unit { font-size: .46em; margin-left: 3px; }
  .ud-metrics .ud-arrow { color: #c8d4d6; font-size: .65em; font-weight: 400; }
  .ud-metrics .ud-bars { display: flex; align-items: flex-end; gap: clamp(6px,1.8cqi,12px); height: clamp(58px, 15cqi, 92px); padding-top: 4px; margin-top: 24px; }
  .ud-metrics .ud-bar { flex: 1; height: var(--height); background: linear-gradient(#40eb88, #23b967); border-radius: 2px 2px 0 0; transform-origin: bottom; }
  .ud-metrics .ud-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
  .ud-metrics .ud-card.ud-animate { animation: ud-enter .8s cubic-bezier(.2,.7,.2,1) both; }
  .ud-metrics .ud-animate::after { animation: ud-sheen 1.5s .2s ease-out both; }
  .ud-metrics .ud-animate .ud-line { stroke-dasharray: 1; stroke-dashoffset: 1; animation: ud-draw 1.5s .25s ease-out forwards; }
  .ud-metrics .ud-animate .ud-area, .ud-metrics .ud-animate .ud-dot { animation: ud-fade 1.6s .25s both; }
  .ud-metrics .ud-animate .ud-progress { animation: ud-fill 1.7s .2s cubic-bezier(.16,1,.3,1) both; }
  .ud-metrics .ud-animate .ud-bar { animation: ud-grow 1s calc(.15s + var(--index) * .07s) cubic-bezier(.2,.7,.2,1) both; }
  @keyframes ud-enter { from { opacity: 0; transform: translateY(24px) scale(.975); } to { opacity: 1; transform: none; } }
  @keyframes ud-sheen { to { transform: translateX(110%); } }
  @keyframes ud-draw { to { stroke-dashoffset: 0; } }
  @keyframes ud-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  @keyframes ud-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
  @keyframes ud-fade { from { opacity: 0; } to { opacity: 1; } }
  @container (max-width: 380px) { .ud-metrics { grid-template-columns: 1fr; gap: 18px; } }
  /* in a half-page column the two by two still fits, but only with the air
     between the parts taken back */
  @container (max-width: 560px) {
    .ud-metrics { gap: 14px; }
    .ud-metrics .ud-heading { margin-bottom: 16px; padding-bottom: 13px; }
    .ud-metrics .ud-icon { width: 22px; height: 22px; }
    .ud-metrics .ud-change { margin-top: 14px; }
    .ud-metrics .ud-detail { margin-top: 6px; }
    .ud-metrics .ud-chart, .ud-metrics .ud-bars { margin-top: 14px; }
    .ud-metrics .ud-footer { padding-top: 16px; }
    .ud-metrics .ud-card { border-radius: 20px; }
  }
  @media (prefers-reduced-motion: reduce) { .ud-metrics *, .ud-metrics *::after { animation: none !important; } }
/* it sits inside a deliverable's art column, so the column's own frame and
   glow have nothing to draw here */
.ap-case-deliv-art:has(.ud-metrics){border:0; background:none; box-shadow:none; overflow:visible;
  /* the cards size against this column, not the viewport: they are half
     the page wide here and the standalone build assumed the whole of it */
  container-type:inline-size}
.ap-case-deliv-art.is-bare:has(.ud-metrics)::before{display:none}
