/* components part 12 of 16 — split for the host's 16KB FTP ceiling.
   Generated by split_for_ftp.py; edit the prototype, not this. */
@media(max-width:820px){
  .tst,.tst.solo{grid-template-columns:minmax(0,1fr)}
  /* one column here, so the desktop right-column placement would create a phantom second */
  .tst.solo .tst-body{grid-column:1}
  .tst-media{height:clamp(280px,68vw,420px);min-height:clamp(280px,68vw,420px)}
  .tst-head{align-items:flex-start}
  .tst-logo{margin-left:0;width:calc(96px * var(--logo-scale,1))}}
.tst-ph-ph{width:54px;height:54px;border-radius:50%;flex:0 0 auto;display:flex;align-items:center;justify-content:center;background:var(--grey);border:1px solid var(--hair);color:var(--faint)}
.tst-ph-ph svg{width:24px;height:24px}@media(min-width:1180px){
  .tst-ph,.tst-ph-ph{width:64px;height:64px}
  .tst-ph-ph svg{width:28px;height:28px}
  .tst-logo{width:calc(132px * var(--logo-scale,1))}}
.tst-mi img,.tst-media>img{cursor:zoom-in}
/* Floats under the header on scroll, same idea as .pf-side on /portfolio/ (a horizontal
   strip pinned at the sticky header's real height, kept in sync in --head-h). Only two
   short rows here, so no collapse/scroll-inside machinery is needed, just the pin. */
.tst-filters{position:sticky;top:var(--head-h);z-index:40;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:14px;margin:0 0 clamp(26px,3.2vw,40px);padding-block:14px;background:rgba(255,255,255,.82);backdrop-filter:blur(18px) saturate(1.3);-webkit-backdrop-filter:blur(18px) saturate(1.3);border-bottom:1px solid rgba(20,19,14,.07)}
/* The reviews filter strip sticks under the header, so it is the same frosted glass as the header
   (Siim, 10 Oct 2026); the pills stay solid white. Header went .72 to .82 the same day. */
.tst-frow{display:flex;flex-wrap:wrap;gap:8px}@media(max-width:900px){
  .tst-head{grid-template-columns:minmax(0,1fr)}
  /* Mobile reverts to left: this is where it stacks under the H1 and picks up the sitewide
     bled/scroll treatment, which is built to sit flush with the left edge like everything
     else on a phone, not the desktop-only right-alignment above. */
  .tst-side{align-items:flex-start;text-align:left;gap:22px;margin-top:22px}
  /* Same 50%-resolves-against-this-box trap as .clients above: capped at 640px, this
     column's centre sat 24px left of the viewport's, so the bled .client-rating row
     started 24px left of the H1 instead of flush under it. The paragraph keeps its own
     48ch measure, so dropping the cap here only lets the H1 use the full gutter width. */
  .tst-head-txt{max-width:none}}
/* WIDE ROWS (.cardgrid.rows): one card per row, big image left, text right. Siim, 25 Sep:
   the 4-up cards read as "micro small tabs" for What else comes off the same model
   (industries), What we model (3D modeling) and Other locations. Works for both card
   kinds, .mini.svc (svc-img/svc-body) and .mini.why (why-img/why-body). Phones: two
   columns, the same as the homepage grid, not the sideways swipe of .cardgrid.four. */
.cardgrid.rows{grid-template-columns:minmax(0,1fr)}
.cardgrid.rows>.mini{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);align-items:stretch;position:relative;padding:0}
.cardgrid.rows>.mini>img{width:100%;height:auto;min-height:0;aspect-ratio:16/10;object-fit:cover;border-radius:0;margin:0}
.cardgrid.rows>.mini>div{display:flex;flex-direction:column;justify-content:center;padding:clamp(28px,3.4vw,56px)}
.cardgrid.rows>.mini h3{font-size:clamp(22px,2vw,28px)}
.cardgrid.rows>.mini p{font-size:16.5px;max-width:52ch}
.cardgrid.rows>.mini .svc-more{margin-top:18px}
.cardgrid.rows>.mini .svc-more::after{content:"";position:absolute;inset:0;z-index:1}@media(max-width:900px){
  .cardgrid.rows{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  .cardgrid.rows>.mini{display:flex;flex-direction:column}
  .cardgrid.rows>.mini>img{height:auto;min-height:0;aspect-ratio:4/3}
  .cardgrid.rows>.mini>div{justify-content:flex-start;padding:14px 14px 18px}
  .cardgrid.rows>.mini h3{font-size:16px}
  .cardgrid.rows>.mini p{font-size:14px}
  .cardgrid.rows>.mini .svc-more{margin-top:10px;font-size:11px}}
/* CLIENT QUOTE CARDS (.mini.rev-card), location pages (_location._reviews): the quote in
   the site's .whatis-quote style, then the reviewer's photo, name and company. */
.mini.rev-card{display:flex;flex-direction:column;justify-content:space-between;gap:22px;padding:clamp(24px,2.6vw,36px)}
.mini.rev-card .whatis-quote{margin:0}
/* CASE STUDY PAGES (/case-studies/<slug>/, Siim 25 Sep 2026: "cannot just use the service page
   fluff"; structure from content/case-studies/RESEARCH.md). A full-bleed hero with 3 labels,
   then ONE section holding a sticky client profile (.cs-side) next to the opening and the
   chapters (.cs-main), so the profile stays in view through the story and is released before
   the full-width sections. Reuses .rev-by, .ba, .head, .timeline, .cardgrid/.mini.svc, .btn-p.
   On phones the profile is a compact card, the details a closed <details>, and the chapter
   list a sticky row of chips under the header. Built by pages/_case_study.py. */
/* Pulled up under the sticky header (the bar is transparent over it, see body.head-over). */
.cs-hero{position:relative;width:100%;max-width:var(--maxbleed);margin:calc(-1 * var(--head-h,81px)) auto 0;min-height:clamp(460px,72vh,780px);
  display:flex;align-items:flex-end;overflow:hidden;background:var(--dark)}
.cs-hero>img.hero-img{position:absolute;inset:0;width:100%;height:100%;min-height:0;aspect-ratio:auto;object-fit:cover}
.cs-hero::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(20,19,16,0) 35%,rgba(20,19,16,.34) 62%,rgba(20,19,16,.78) 100%)}
.cs-hero-txt{position:relative;z-index:1;width:100%;padding-bottom:clamp(34px,5vw,68px)}
.cs-hero .crumb a,.cs-hero .crumb span[aria-current]{color:rgba(255,255,255,.88)}
.cs-hero .crumb span[aria-hidden]{color:rgba(255,255,255,.5)}
.cs-hero h1{color:#fff;font-size:clamp(42px,6vw,88px);letter-spacing:-0.035em;line-height:.98;margin:14px 0 0;max-width:15ch}
.cs-hero h1 .h1-lite{display:block;font-weight:400;letter-spacing:-0.015em;font-size:.4em;line-height:1.2;margin-top:.5em;max-width:32ch;opacity:.94}
.cs-labels{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:22px 0 0;padding:0}
.cs-labels li{font-size:13px;font-weight:600;line-height:1;color:#fff;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.36);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);border-radius:999px;padding:9px 14px}
.cs-body{display:grid;grid-template-columns:minmax(0,280px) minmax(0,1fr);gap:clamp(40px,5vw,88px)}
.cs-prof{position:sticky;top:calc(var(--head-h) + 24px);max-height:calc(100vh - var(--head-h) - 40px);overflow-y:auto;scrollbar-width:thin;
  display:flex;flex-direction:column;gap:16px}
.cs-card{display:flex;flex-direction:column;gap:14px;padding-top:16px;border-top:2px solid var(--ink)}
.cs-co{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:1.45;color:var(--body)}
.cs-co b{font-size:16px;color:var(--ink)}
.cs-co a{color:var(--accent-d);font-weight:600;margin-top:2px}
.cs-co a:hover{text-decoration:underline;text-underline-offset:2px}
.cs-logo{display:block;height:24px;margin-bottom:10px;color:var(--ink)}
.cs-logo svg,.cs-logo img{display:block;height:100%;width:auto;max-width:180px}
.cs-card .rev-by{padding-top:14px;border-top:1px solid var(--hair)}
.cs-who-note{margin:-6px 0 0;font-size:13.5px;line-height:1.45;color:var(--muted)}
.cs-since{margin:0;padding-top:12px;border-top:1px solid var(--hair);font-size:14px;color:var(--muted)}
.cs-since b{display:block;font-family:var(--disp);font-size:18px;font-weight:650;letter-spacing:-0.02em;line-height:1.2;color:var(--ink);margin-bottom:2px}
.cs-details summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);padding-bottom:8px;border-bottom:1px solid var(--hair)}
.cs-details summary::after{content:"+";font-size:18px;line-height:.8;color:var(--accent)}
.cs-details[open] summary::after{content:"\2212"}
.cs-details summary::-webkit-details-marker{display:none}
.cs-details dl{margin:0}
.cs-details dl>div{display:grid;grid-template-columns:92px minmax(0,1fr);gap:10px;padding:6px 0;border-bottom:1px solid var(--hair);font-size:13.5px;line-height:1.42}
.cs-details dt{color:var(--muted);font-weight:600}
.cs-details dd{margin:0;color:var(--ink);font-weight:500}@supports selector(::details-content){@media(min-width:901px) and (min-height:880px){
  .cs-details::details-content{content-visibility:visible;display:block}
  .cs-details summary{cursor:default;pointer-events:none}
  .cs-details summary::after{content:none}
}}
.cs-toc{display:flex;flex-direction:column}
.cs-toc a{display:flex;gap:12px;align-items:baseline;padding:5px 0;font-size:14.5px;font-weight:600;line-height:1.3;color:var(--ink)}
.cs-toc a span{font-size:11.5px;font-weight:700;letter-spacing:.08em;color:var(--accent);font-variant-numeric:tabular-nums}
.cs-toc a:hover{color:var(--accent-d)}
.cs-prof>.btn{justify-content:center}
.cs-main{min-width:0}
.cs-opening{max-width:800px}
.cs-opening .cs-big{font-family:var(--disp);font-size:clamp(21px,1.8vw,26px);line-height:1.3;letter-spacing:-0.02em;color:var(--ink);font-weight:500;margin:0 0 30px}
.cs-q{margin:0 0 22px;max-width:none;font-family:var(--disp);font-size:clamp(23px,2.2vw,32px);line-height:1.24;letter-spacing:-0.025em;color:var(--ink);font-weight:500}
.cs-q p{margin:0 0 .5em}
.cs-q .cs-hl{color:var(--accent-d)}
.cs-opening>.rev-by{margin:0 0 30px}
.cs-opening>p:not(.cs-big),.cs-ch>p{font-size:17px;line-height:1.7;color:var(--body);margin:0 0 16px;max-width:66ch}
.cs-ch{margin-top:clamp(52px,5.4vw,84px);padding-top:clamp(40px,4vw,60px);border-top:1px solid var(--hair);scroll-margin-top:calc(var(--head-h) + 16px)}
.cs-ch>.eyebrow{margin-bottom:0}
.cs-main .cs-ch>h2{font-size:clamp(28px,2.8vw,40px);line-height:1.05;margin:10px 0 14px}
.cs-figs{display:grid;gap:clamp(12px,1.4vw,20px);margin-top:clamp(22px,2.4vw,32px)}
.cs-grid{display:grid;grid-template-columns:repeat(var(--n,4),minmax(0,1fr));gap:clamp(10px,1.2vw,16px)}
.cs-figs figure,.cs-grid figure{margin:0}
.cs-figs img,.cs-grid img{display:block;width:100%;height:auto;border-radius:6px;cursor:zoom-in;background:var(--grey)}
.cs-figs .ba{aspect-ratio:16/9;border-radius:6px}
.cs-figs .ba img{height:100%;border-radius:0;cursor:ew-resize}
.cs-two,.cs-pair{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(12px,1.4vw,20px);align-items:start}