/* pack3d.css: a turnable CSS 3D model of the Daily Bread pack, textured from photographs of it.
   Markup and rules: pack3d.md. Behaviour: pack3d.js (photos, buttons) and pack3d.model.js (the model). Uses v3.css tokens when present, with OKLCH fallbacks (no hex, no rgb).
   Box proportions are measured from the photographs (length : height : depth = 1.16 : 1.00 : 0.89). */

.pack3d {
  --pack3d-max: 28rem;                              /* the stage never grows past this (texture limit) */
  --pack3d-ink: 0.21 0.008 75;                      /* Kitchen Ink as OKLCH channels, for shading and the floor shadow */
  --pack3d-floor: 0.34;
  margin: 0;
  max-width: var(--pack3d-max);
}
html[data-theme="dark"] .pack3d { --pack3d-ink: 0.13 0.004 70; --pack3d-floor: 0.5; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) .pack3d { --pack3d-ink: 0.13 0.004 70; --pack3d-floor: 0.5; }
}

/* The group holds the stage and the buttons; it takes focus for the arrow keys. */
.pack3d__group { border-radius: var(--cut, 2px); }
.pack3d__group:focus-visible { outline: 2px solid var(--focus-ink, oklch(0.21 0.008 75)); outline-offset: 3px; }

/* Dimension-locked: a square that never changes size, whatever it shows. */
.pack3d__stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  container-type: inline-size;
  --H: calc(var(--pack3d-max) * 0.44);              /* pack height; overridden by the container unit below */
  touch-action: pan-y;                              /* a vertical swipe still scrolls the page on phones */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
@supports (width: 1cqi) {
  .pack3d__stage { --H: 44cqi; }
}

/* The still: a photograph of the chosen side (no JavaScript, reduced motion, Save-Data, or until the model is ready). */
.pack3d__still {
  position: absolute;
  inset: 4%;
  width: 92%;
  height: 92%;
  object-fit: contain;
  filter: var(--shadow-held, drop-shadow(0 18px 18px oklch(0.21 0.008 75 / 0.18)));
}
.pack3d.is-3d .pack3d__still { visibility: hidden; }

/* ---------------------------------------------------------------- the model */
.pack3d__view {
  position: absolute;
  inset: 0;
  perspective: calc(var(--H) * 7);
  perspective-origin: 50% 40%;
  opacity: 0;
  transition: opacity 280ms var(--ease-quart, cubic-bezier(0.25, 1, 0.5, 1));
}
.pack3d.is-3d .pack3d__view { opacity: 1; }
.pack3d.is-3d .pack3d__stage { cursor: grab; }
.pack3d.is-dragging .pack3d__stage { cursor: grabbing; }

.pack3d__model {
  --L: calc(var(--H) * 1.16);
  --D: calc(var(--H) * 0.89);
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0;
  height: 0;
  transform-style: preserve-3d;
  transform: translateY(calc(var(--H) * 0.2)) rotateX(-5deg) rotateY(-24deg);
}

.pack3d__f {
  position: absolute;
  left: calc(var(--w) / -2 - 0.5px);
  top: calc(var(--h) / -2 - 0.5px);
  width: calc(var(--w) + 1px);                      /* half a pixel of overlap hides seams at the edges */
  height: calc(var(--h) + 1px);
  transform: var(--t);
  backface-visibility: hidden;
}
.pack3d__f::before,
.pack3d__f::after { content: ""; position: absolute; inset: 0; }
.pack3d__f::before { background: var(--img) center / 100% 100% no-repeat; }
/* Light: a key light above and in front, a little to the left. pack3d.js sets --s per side as the pack turns. */
.pack3d__f::after { background-color: oklch(var(--pack3d-ink) / var(--s, 0.15)); }
/* The ends carry the bag film at their top corners (16% alpha): shade only what the photo shows. */
.pack3d__f--front::after,
.pack3d__f--inside::after {
  -webkit-mask: var(--img) center / 100% 100% no-repeat;
  mask: var(--img) center / 100% 100% no-repeat;
}
/* The long sides: a wall plus three shoulder facets, each showing its own band of the same side photo.
   pack3d.js sets the geometry (--h, --t) and the band (--bs size, --bp position) from the measured shoulder. */
.pack3d__f--band::before { background-size: 100% var(--bs, 100%); background-position: 0 var(--bp, 0%); }

/* Sides: a soft darkening near the floor and at the corners, where the bag rounds over the loaf. */
.pack3d__f--side::after {
  background-image:
    linear-gradient(to top, oklch(var(--pack3d-ink) / 0.2), transparent 22%),
    linear-gradient(to bottom, oklch(var(--pack3d-ink) / 0.1), transparent 5%),
    linear-gradient(to right, oklch(var(--pack3d-ink) / 0.18), transparent 6%, transparent 94%, oklch(var(--pack3d-ink) / 0.18));
}

.pack3d__f--front  { --w: var(--D); --h: var(--H); --t: translateZ(calc(var(--L) / 2)); }
.pack3d__f--inside { --w: var(--D); --h: var(--H); --t: rotateY(180deg) translateZ(calc(var(--L) / 2)); }
.pack3d__f--label,
.pack3d__f--back   { --w: var(--L); }                /* walls: height and transform set by pack3d.js */

/* Top and bottom were never photographed: small crust samples from the same photos stand in for them.
   The top spans only the crown between the shoulders (pack3d.js sets its width), so it never overhangs the bag film. */
.pack3d__f--top    { --w: var(--D); --h: var(--L); --t: rotateX(90deg) translateZ(calc(var(--H) / 2)); border-radius: 5% / 4%; overflow: hidden; }
.pack3d__f--bottom { --w: var(--D); --h: var(--L); --t: rotateX(-90deg) translateZ(calc(var(--H) / 2)); }
.pack3d__f--top::before,
.pack3d__f--bottom::before { background-repeat: repeat; background-position: center; }
.pack3d__f--top::before { background-size: calc(var(--H) * 0.227) calc(var(--H) * 0.132); }    /* 100 x 58 px tile at 440 px per H */
.pack3d__f--bottom::before { background-size: calc(var(--H) * 0.491) calc(var(--H) * 0.1); }  /* 216 x 44 px tile */
.pack3d__f--top::after {
  /* Lighting only: the clear bag's gloss catching the key light, the shade where the bag gathers under the
     header, and a darker rim where the crown rounds away. */
  background-image:
    linear-gradient(125deg, transparent 18%, oklch(0.968 0.004 85 / 0.16) 30%, transparent 44%),
    linear-gradient(to right, oklch(var(--pack3d-ink) / 0.22) 0, transparent 14%, oklch(var(--pack3d-ink) / 0.42) 50%, transparent 86%, oklch(var(--pack3d-ink) / 0.22) 100%),
    linear-gradient(to bottom, oklch(var(--pack3d-ink) / 0.18), transparent 10%, transparent 90%, oklch(var(--pack3d-ink) / 0.18));
}

/* The kraft header: a strip folded over the bag mouth, two leaves meeting at the fold. */
.pack3d__f--hdr-a,
.pack3d__f--hdr-b { --w: calc(var(--H) * var(--hw, 1.705)); --h: calc(var(--H) * var(--hh, 0.417)); }
.pack3d__f--hdr-a {
  --t: translateY(calc(var(--H) / -2)) rotateY(-90deg) translateZ(calc(var(--h) * 0.035)) rotateX(2deg) translateY(calc(var(--h) / -2));
}
.pack3d__f--hdr-b {
  --t: translateY(calc(var(--H) / -2)) rotateY(90deg) translateZ(calc(var(--h) * 0.035)) rotateX(2deg) translateY(calc(var(--h) / -2));
}
.pack3d__f.is-mirror::before { transform: scaleX(-1); }
.pack3d__f--hdr-a::after,
.pack3d__f--hdr-b::after { background-image: linear-gradient(to top, oklch(var(--pack3d-ink) / 0.16), transparent 30%); }

/* The floor under the pack: a tight contact shadow and a soft one. Drawn, not photographed.
   Floor plane = 1.9 D x 1.7 L, so the base footprint is inset 23.7% (sides) and 20.6% (ends). */
.pack3d__f--floor {
  --w: calc(var(--D) * 1.9);
  --h: calc(var(--L) * 1.7);
  --t: translateY(calc(var(--H) / 2 + 1px)) rotateX(90deg);
  backface-visibility: visible;
}
.pack3d__f--floor::before,
.pack3d__f--floor::after { content: ""; border-radius: 8%; }
.pack3d__f--floor::before {                         /* contact: just wider than the base, dark, tight */
  inset: 19.2% 22.2%;
  background: oklch(var(--pack3d-ink) / calc(var(--pack3d-floor) * 1.8));
  filter: blur(calc(var(--H) * 0.014));
}
.pack3d__f--floor::after {                          /* soft: wider, lighter, falling back and right, away from the key light */
  inset: 11% 14%;
  background: oklch(var(--pack3d-ink) / var(--pack3d-floor));
  filter: blur(calc(var(--H) * 0.07));
  transform: translate(3%, -3%);
}

/* ---------------------------------------------------------------- buttons */
.pack3d__buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--s-md, 1rem);
  margin-top: var(--s-sm, 0.75rem);
}
.pack3d__btn {
  position: relative;
  min-width: var(--tap, 2.75rem);                   /* 44px hit area both ways: "Back" is only 37px of text */
  min-height: var(--tap, 2.75rem);
  padding: 0;
  text-align: start;                                /* short labels stay put; the band starts where the word does */
  border: 0;
  background: none;
  color: var(--ink-text, oklch(0.21 0.008 75));
  font-family: var(--font-print, Georgia, serif);
  font-size: var(--t-label, 0.9375rem);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.01em;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.pack3d__btn > span {
  background-image: linear-gradient(var(--swipe, oklch(0.797 0.163 88.1)), var(--swipe, oklch(0.797 0.163 88.1)));
  background-repeat: no-repeat;
  background-position: 0 88%;
  background-size: 0% 55%;
  transition: background-size 200ms var(--ease-quart, cubic-bezier(0.25, 1, 0.5, 1));
}
.pack3d__btn[aria-pressed="true"] > span { background-size: 100% 55%; }
@media (hover: hover) and (pointer: fine) {
  .pack3d__btn:hover > span { text-decoration: underline 2px var(--link-line, oklch(0.797 0.163 88.1)); text-underline-offset: 4px; }
  .pack3d__btn[aria-pressed="true"]:hover > span { text-decoration: none; }
}
.pack3d__btn:active { transform: scale(0.97); }
.pack3d__btn--turn { margin-right: auto; }
@media (min-width: 600px) { .pack3d__btn--turn { margin-left: auto; margin-right: 0; } }
@media (forced-colors: active) {
  .pack3d__btn[aria-pressed="true"] > span { text-decoration: underline 2px; text-underline-offset: 4px; }
}

.pack3d__caption {
  margin-top: var(--s-xs, 0.5rem);
  font-size: var(--t-fine, 0.9375rem);
  line-height: 1.5;
  color: var(--pencil-text, oklch(0.47 0.008 75));
}
.pack3d__caption [data-when="model"] { display: none; }
.pack3d.is-3d .pack3d__caption [data-when="model"] { display: inline; }
.pack3d.is-3d .pack3d__caption [data-when="still"] { display: none; }

html[data-motion="none"] .pack3d__view,
html[data-motion="none"] .pack3d__btn > span { transition: none; }
