/* ============================================================
   characters.css — GTA-Style Character Design service page.
   Page-scoped (ch- prefix); shared tokens come from styles.css.
   The gallery + viewer carry the energy; the chrome stays quiet.
   ============================================================ */

/* ---------- Hero ---------- */
.ch-hero__sub{
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:28px;margin-top:clamp(26px,4vw,48px);
}
.ch-hero__sub p{max-width:46ch;font-size:clamp(16px,1.6vw,21px);line-height:1.55}
.ch-hero__cta{display:flex;align-items:center;gap:clamp(16px,2vw,28px);flex:none;flex-wrap:wrap}
.ch-hero__more{
  font-family:var(--mono);font-size:12px;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--muted);transition:color .2s;
}
.ch-hero__more:hover{color:var(--blue)}

/* ---------- Sample gallery ----------
   Slots are plain <img> tags in framed fields. A missing file is
   hidden by site.js's global error handler, so the labeled field
   shows through — swapping in finals is a pure file drop. */
.ch-gallery{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(14px,2vw,24px);
}
.ch-shot{margin:0;min-width:0}
.ch-shot--wide{grid-column:1 / -1}
.ch-shot__frame{
  position:relative;
  border:1px solid var(--line);
  background:#fff;
  overflow:hidden;
}
.ch-shot__frame img{
  position:relative;z-index:1;
  width:100%;aspect-ratio:4/5;object-fit:cover;object-position:top;
}
.ch-shot--wide .ch-shot__frame img{aspect-ratio:16/8}
.ch-shot__ph{
  position:absolute;inset:0;z-index:0;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:10px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--mist);text-align:center;padding:20px;
  background:
    linear-gradient(var(--paper),var(--paper)) padding-box,
    repeating-linear-gradient(-45deg,rgba(21,21,27,0.03) 0 14px,transparent 14px 28px) padding-box;
  background-blend-mode:multiply;
}
.ch-shot__cap{
  font-family:var(--mono);font-size:10px;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--muted);margin-top:10px;
}

/* ---------- Featured 3D viewer ---------- */
.ch-viewer{
  display:grid;
  grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);
  align-items:start;
}
.ch-stage{
  position:relative;
  border:1px solid var(--line);
  background:#fff radial-gradient(ellipse 70% 55% at 50% 42%,#ffffff 0%,#f7f6f2 100%);
  padding:0 clamp(14px,1.6vw,22px);
  user-select:none;-webkit-user-select:none;
}
.ch-canvas{
  width:100%;
  height:clamp(420px,62vh,680px);
  display:block;
  touch-action:pan-y;             /* one-finger vertical swipes scroll; drag + pinch are ours */
  cursor:grab;
  opacity:0;
  transition:opacity .8s ease;
  outline-offset:-4px;
}
.ch-canvas:active{cursor:grabbing}
.ch-3d-on .ch-canvas{opacity:1}
.ch-3d-failed .ch-canvas{display:none}

/* Loading line — visible only between boot and first render */
.ch-load{
  position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  text-align:center;
  font-family:var(--mono);font-size:11px;letter-spacing:0.18em;text-transform:uppercase;
  color:var(--mist);pointer-events:none;
  opacity:0;transition:opacity .4s ease;
}
.ch-3d-loading .ch-load{opacity:1}

/* Static fallback — replaces the canvas if WebGL / modules fail */
.ch-fallback{
  display:none;
  flex-direction:column;align-items:center;justify-content:center;gap:22px;
  min-height:clamp(360px,52vh,560px);
  padding:32px;text-align:center;
}
.ch-3d-failed .ch-fallback{display:flex}
.ch-fallback img{max-height:min(46vh,420px);width:auto;max-width:100%}
.ch-fallback p{
  font-family:var(--mono);font-size:11px;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--muted);max-width:34ch;line-height:1.7;
}

/* Interaction hint — fades after first touch */
.ch-hint{
  position:absolute;top:clamp(12px,1.6vw,20px);right:clamp(14px,1.6vw,22px);
  font-family:var(--mono);font-size:11px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--muted);pointer-events:none;
  opacity:0;transition:opacity .6s ease;
}
.ch-3d-on .ch-hint{opacity:1}
.ch-3d-on .ch-hint.is-done{opacity:0}
.ch-hint em{font-style:normal;color:var(--blue)}

/* Honest chip while the temporary stand-in model is on stage.
   Sits bottom-left of the canvas so it never collides with the hint. */
.ch-temp{
  position:absolute;bottom:58px;left:clamp(14px,1.6vw,22px);
  display:none;
  font-family:var(--mono);font-size:10px;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--mist);pointer-events:none;max-width:26ch;line-height:1.6;
}
.ch-3d-placeholder .ch-temp{display:block}

/* Viewer toolbar */
.ch-tools{
  display:flex;flex-wrap:wrap;align-items:center;gap:2px clamp(14px,1.6vw,26px);
  padding:14px 0 12px;border-top:1px solid var(--line);
}
.ch-tools button{
  appearance:none;background:none;border:none;padding:6px 0;
  font-family:var(--mono);font-size:11px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--muted);cursor:pointer;
  border-bottom:1px solid transparent;
  transition:color .2s,border-color .2s;
}
.ch-tools button:hover{color:var(--blue);border-bottom-color:var(--blue)}
.ch-live{
  margin-left:auto;
  font-family:var(--mono);font-size:10px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--mist);
}
.ch-3d-failed .ch-tools{display:none}
.ch-3d-failed .ch-hint{display:none}

/* Viewer copy rail */
.ch-viewer__lede{
  font-size:clamp(19px,2vw,28px);line-height:1.35;letter-spacing:-0.01em;font-weight:600;
  max-width:34ch;
}
.ch-viewer__desc{
  margin-top:clamp(18px,2.4vw,28px);max-width:44ch;
  font-size:clamp(15px,1.4vw,18px);line-height:1.6;color:var(--muted);
}
.ch-viewer__specs{
  list-style:none;margin:clamp(24px,3vw,36px) 0 0;padding:0;
  display:flex;flex-wrap:wrap;gap:8px;
}
.ch-viewer__specs li{
  font-family:var(--mono);font-size:11px;letter-spacing:0.1em;text-transform:uppercase;
  padding:6px 12px;border:1px solid var(--line);border-radius:999px;color:var(--muted);
}

/* ---------- Deliverables extras ---------- */
.ch-uses{
  margin-top:clamp(22px,3vw,32px);
  font-family:var(--mono);font-size:11px;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);line-height:2;
}

/* ---------- Small print ---------- */
.ch-smallprint{
  margin-top:clamp(24px,3vw,40px);
  font-family:var(--mono);font-size:10px;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--mist);
}

/* ---------- Responsive ---------- */
@media (max-width:900px){
  .ch-gallery{grid-template-columns:1fr}
  .ch-shot--wide .ch-shot__frame img{aspect-ratio:16/9}
  .ch-viewer{grid-template-columns:1fr;gap:clamp(24px,5vw,40px)}
  .ch-canvas{height:min(58svh,520px);min-height:340px}
  .ch-hint{font-size:10px;letter-spacing:0.12em}
  .ch-live{display:none}
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  .ch-canvas{transition:none}
}

/* ============================================================
   Turnaround stills turntable + details row (2026-08-27 pivot:
   the artwork is the product; the turntable steps through the
   four hand-finished views — honestly labeled, no fake 3D).
   ============================================================ */
.ch-turn{padding:0 clamp(14px,1.6vw,22px)}
.ch-turn__stage{
  position:relative;
  height:clamp(420px,60vh,640px);
  display:flex;align-items:flex-end;justify-content:center;
  touch-action:pan-y;
  cursor:grab;
}
.ch-turn__stage:active{cursor:grabbing}
.ch-turn__img{
  position:absolute;bottom:34px;left:50%;transform:translateX(-50%);
  height:calc(100% - 70px);width:auto;max-width:none;
  opacity:0;transition:opacity .18s ease;
  pointer-events:none;
  user-select:none;-webkit-user-drag:none;
}
.ch-turn__img.is-active{opacity:1}
.ch-turn__shadow{
  position:absolute;bottom:22px;left:50%;transform:translateX(-50%);
  width:min(46%,240px);height:26px;border-radius:50%;
  background:radial-gradient(ellipse at center,rgba(21,21,27,0.28) 0%,rgba(21,21,27,0) 68%);
}
.ch-turn__tag{
  position:absolute;bottom:58px;left:clamp(14px,1.6vw,22px);
  font-family:var(--mono);font-size:10px;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--mist);max-width:24ch;line-height:1.6;pointer-events:none;
}
.ch-turn__view{
  font-family:var(--mono);font-size:11px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--blue);min-width:5ch;
}
.ch-turn .ch-hint{opacity:1}
.ch-turn.is-touched .ch-hint{opacity:0}

/* hero sheet keeps its natural aspect (no crop) */
.ch-shot--sheet .ch-shot__frame img{aspect-ratio:auto;object-fit:contain;background:#fff}

/* details row */
.ch-details{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(14px,2vw,24px);
  margin-top:clamp(24px,3.5vw,44px);
}
.ch-detail{margin:0;min-width:0}
.ch-detail__frame{
  border:1px solid var(--line);background:#fff;overflow:hidden;
}
.ch-detail__frame img{
  width:100%;aspect-ratio:5/4;object-fit:cover;
  image-rendering:auto;
}
@media (max-width:900px){
  .ch-turn__stage{height:min(56svh,520px);min-height:340px}
  .ch-details{grid-template-columns:1fr;max-width:420px}
  .ch-turn__tag{display:none}
}

/* ============================================================
   Scroll-scrubbed rotation centerpiece (2026-08-27):
   sticky stage right, copy rail left — same architecture as
   the /3d page. Scroll progress through the section drives the
   48-frame rendered rotation on the canvas.
   ============================================================ */
.ch-scrub{
  display:grid;
  grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr);
  gap:clamp(24px,4vw,72px);
  padding:0 clamp(20px,5vw,72px);
  max-width:var(--wrap);margin:0 auto;
  border-top:1px solid var(--line);
}
.ch-scrub__right{grid-column:2;grid-row:1}
.ch-scrub__left{grid-column:1;grid-row:1}

.ch-scrub__sticky{
  position:sticky;top:60px;
  height:calc(100vh - 60px);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
}
.ch-scrub__figure{
  position:relative;
  height:min(78vh,860px);
  /* matches the cropped transparent frames (466x1048) */
  aspect-ratio:466/1048;max-width:100%;
}
/* soft ground contact shadow: the frames are cutouts, so the floor
   shadow that grounded the old renders has to live here instead */
.ch-scrub__figure::after{
  content:"";position:absolute;left:50%;bottom:1.5%;
  width:62%;height:4.5%;transform:translateX(-50%);
  background:radial-gradient(ellipse 50% 50% at 50% 50%,rgba(21,21,27,.22),rgba(21,21,27,0) 70%);
  pointer-events:none;
}
.ch-scrub__still,
.ch-scrub__canvas{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;display:block;
}
.ch-scrub__canvas{opacity:0;transition:opacity .5s ease}
.ch-scrub.is-live .ch-scrub__canvas{opacity:1}
.ch-scrub.is-live .ch-scrub__still{opacity:0;transition:opacity .5s ease}
.ch-scrub__note{
  margin-top:6px;
  font-family:var(--mono);font-size:10px;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--mist);
}

/* copy rail: generous runway so the full turn takes real scrolling */
.ch-scrub__left{padding:clamp(56px,14vh,140px) 0 clamp(72px,18vh,180px)}
.ch-scrub__block{min-height:92vh;display:flex;flex-direction:column;justify-content:center}
.ch-scrub__block h2{
  font-weight:700;font-size:clamp(34px,4.6vw,64px);letter-spacing:-0.04em;line-height:0.95;
}
.ch-scrub__block h3{
  font-weight:700;font-size:clamp(26px,3.2vw,44px);letter-spacing:-0.03em;line-height:1;margin:0;
}
.ch-scrub__block p{
  margin-top:clamp(16px,2vw,24px);max-width:38ch;
  font-size:clamp(15px,1.5vw,19px);line-height:1.6;color:var(--muted);
}
.ch-scrub__block .eyebrow{margin-bottom:clamp(14px,2vw,22px)}
.ch-scrub__num{
  font-family:var(--mono);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--blue);margin-bottom:clamp(12px,1.6vw,18px);
}

@media (max-width:900px){
  /* stacked: the whole stage column is sticky against the full section,
     so the character stays pinned while the copy scrolls beneath it */
  .ch-scrub{display:block}
  .ch-scrub__right{
    position:sticky;top:60px;z-index:5;
    background:linear-gradient(var(--paper) 90%,rgba(243,242,237,0));
  }
  .ch-scrub__sticky{position:static;height:auto;padding:10px 0 4px}
  .ch-scrub__figure{height:min(54svh,500px)}
  .ch-scrub__note{margin-top:4px}
  .ch-scrub__left{padding-top:12px}
  .ch-scrub__block{min-height:64vh}
  .ch-scrub__block h2{font-size:clamp(30px,8vw,44px)}
}

/* reduced motion: static artwork, no scrub */
@media (prefers-reduced-motion:reduce){
  .ch-scrub .ch-scrub__canvas{display:none}
  .ch-scrub.is-live .ch-scrub__still{opacity:1}
}

/* ============================================================
   In-world scene renders (2026-08-27)
   Lead group shot sets the row height at its natural aspect;
   the two stacked scenes stretch to match it exactly.
   ============================================================ */
.ch-scenes__grid{
  display:grid;
  grid-template-columns:minmax(0,1.9fr) minmax(0,1fr);
  gap:clamp(14px,2vw,24px);
  align-items:stretch;
}
.ch-scene{
  border:1px solid var(--line);background:#fff;overflow:hidden;min-width:0;
}
.ch-scene img{display:block;width:100%;height:100%;object-fit:cover}
.ch-scene--lead img{height:auto}
.ch-scenes__stack{
  display:grid;grid-template-rows:1fr 1fr;
  gap:clamp(14px,2vw,24px);
  min-width:0;
}
@media (max-width:900px){
  .ch-scenes__grid{grid-template-columns:1fr}
  .ch-scenes__stack{grid-template-rows:none}
  .ch-scene img{height:auto}
}

/* ============================================================
   Save-deterrence on character artwork (2026-08-27)
   pointer-events:none keeps right-click / long-press from ever
   targeting the image, so "Save Image As" never appears; the
   drag + touch-callout rules kill drag-out and the iOS save
   sheet. Deters casual saving only — screenshots still exist.
   ============================================================ */
.ch-scene img,
.ch-shot__frame img,
.ch-scrub__figure img,
.ch-scrub__figure canvas{
  pointer-events:none;
  user-select:none;-webkit-user-select:none;
  -webkit-user-drag:none;
  -webkit-touch-callout:none;
}
