/* ---------------------------------------------------------------------------
   Enclosure in three dimensions -- forklift-lithium-battery.html only.

   A page-scoped stylesheet rather than an addition to main.css.  The block is
   on one page and main.css is on all of them; and main.css is the file the
   responsive and image passes are verified against, so keeping an unrelated
   block out of it keeps that verification meaning what it says.

   Everything here uses the site's own tokens, so the block follows a theme
   change instead of pinning its own colours.
   --------------------------------------------------------------------------- */

/* This block needs no rule of its own to stay visible when the site's script
   does not run.  `.reveal` is visible by default in main.css and only
   `initReveal()` hides the sections below the fold, so a blocked or 404
   `main.js` cannot leave the section at `opacity: 0`.

   A scoped `html:not(.js) #enclosure-3d .reveal { opacity: 1 }` lived here
   while the site-wide rule was the other way round -- hide by default, reveal
   from script.  That is now fixed in main.css for every section, so the
   override and the `.js` marker it keyed on are both gone. */

.viewer-3d {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--paper-2);
  /* Load-bearing on narrow screens.  Below 860 px `.grid--2` becomes
     `grid-template-columns: 1fr` -- not `minmax(0, 1fr)` -- so a grid item's
     minimum width falls back to `auto`, i.e. its min-content.  The spec table
     carries `min-width: 620px` (main.css), so without this the column refuses
     to shrink below the table and the whole page scrolls sideways: measured
     640 px of document scroll width at a 390 px viewport, against 390 px before
     this section existed.  `.table-wrap`'s `overflow-x: auto` cannot save it,
     because the column is already wider than the screen by then. */
  min-width: 0;
}

.viewer-3d__panels { min-width: 0; }

/* The stage holds the still, the viewer and the axis indicator, and it is what
   carries the height.  The gradient lives here rather than on the viewer so
   that the still image sits on the same background it was rendered against:
   `object-fit: contain` letterboxes whenever the column's aspect ratio is not
   the poster's, and a band of a different colour beside the picture reads as a
   seam.  Same box, same gradient, so the bands are invisible. */
.viewer-3d__stage {
  position: relative;
  height: 440px;
  /* A gradient rather than the viewer's default flat grey: the enclosure is a
     large flat-sided box and a gradient gives its top face and its front face
     different values, which is what makes the silhouette read as a solid
     rather than as a sticker. */
  background: radial-gradient(115% 95% at 50% 6%, #ffffff 0%, #eef1f5 60%, #e2e7ee 100%);
}

/* The poster.  A real `<img>`, so it renders with no script at all -- which is
   the difference between "the section is a still picture" and "the section is
   an empty grey box".  `contain` rather than `cover` on purpose: the column's
   aspect ratio runs from about 1.14 on a phone to 1.75 on a tablet, and
   `cover` would crop the enclosure at the wide end, which is the one thing
   this section exists to show. */
.viewer-3d__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* The viewer is layered over the still and stays transparent until it has a
   model on screen.  So every failure -- no JavaScript, a blocked module, a 404,
   a slow link, a decode error -- degrades to the still by doing nothing, and
   there is no error path to get wrong.  `opacity`, not `display`: the element
   has to keep laying out and keep its camera, or it would reload the model
   every time the class came back.

   `background: transparent` is what this block is FOR -- the stage's gradient
   shows through and the model sits on it -- and it is also the reason the rule
   below has to exist. */
.viewer-3d model-viewer {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  background: transparent;
  opacity: 0;
  transition: opacity 0.35s ease;
}

.viewer-3d.is-live model-viewer { opacity: 1; }

/* Hide the still once a model is on screen.  Without this the section shows TWO
   enclosures: the still underneath, at the poster's fixed camera angle, and the
   live model over it, at `camera-orbit` and auto-rotating.  Reported by the
   owner as "after switching the voltage there are two models in the picture,
   one rotating and one fixed", and it is worse than it looks -- `select()` only
   swaps the still while `!live`, so after a tab click the still is the PREVIOUS
   voltage's poster and the model is the new one.  Two different products in one
   picture.

   The comment above the markup used to say the viewer "covers the still
   completely".  It cannot: a model-viewer canvas is transparent, so `opacity: 1`
   covers nothing.  Measured 2026-10-06 by hiding the still and diffing the
   stage -- the pixels change (md5 e74cbdf6... -> 3be63bd9...), which is what
   proves the still was being painted rather than merely present.

   `visibility`, not `display`: the image stays decoded, and this is a one-way
   state -- `is-live` is never removed -- so there is nothing to bring back. */
.viewer-3d.is-live .viewer-3d__shot { visibility: hidden; }

.viewer-3d__hint {
  padding: 7px 12px;
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--text-3);
  background: #fff;
  border-top: 1px solid var(--line);
}

.viewer-3d__note { color: var(--text-2); }

/* Which caption is shown, and whether the axis indicator has anything to say,
   is decided here -- off the one class the script adds when a model has
   actually loaded.  Both sentences are in the markup so both are translated;
   switching them with `display` rather than by writing text keeps that true,
   because a string assembled in script stays English in all five trees. */
.viewer-3d:not(.is-live) #hint,
.viewer-3d.is-live #hint-still,
.viewer-3d:not(.is-live) .axes { display: none; }

/* The axis indicator.  SVG, projected to 2D on every camera change -- see the
   note in the page's script for why CSS 3D transforms cannot do this. */
.axes {
  position: absolute;
  left: 10px;
  bottom: 10px;
  width: 88px;
  height: 88px;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.axes text {
  font-size: 10px;
  font-weight: 700;
  font-family: var(--font);
}

/* Voltage tabs.  Sized like `.btn--sm` so they read as the same family as the
   two buttons below them, but not built from `.btn`: `.btn` sets
   `white-space: nowrap` and a fixed `display`, and a wrapping tab row wants
   neither. */
.tabs-3d {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
}

.tabs-3d button {
  font: inherit;
  font-size: 0.86rem;
  font-weight: 650;
  padding: 10px 18px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--text);
  cursor: pointer;
}

.tabs-3d button:hover { border-color: var(--ink-700); background: var(--paper-2); }

.tabs-3d button[aria-pressed="true"] {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: #fff;
}

/* An explicit `display` outranks the user agent's `[hidden] { display: none }`,
   which is a trap this codebase has already paid for twice (see the notes on
   `.result-grid[hidden]` and `.result-list div[hidden]` in main.css).  Nothing
   here sets `display` on `.table-wrap` today, so the attribute would work by
   itself -- but the panels are switched by script, and a silent no-op there
   would show six tables at once.  Written out so it cannot become one. */
.viewer-3d__panels .table-wrap[hidden] { display: none; }

.dims-note {
  font-size: var(--fs-xs);
  color: var(--text-3);
  margin-top: var(--s-3);
}

@media (max-width: 720px) {
  .viewer-3d__stage { height: 300px; }
  .axes { width: 72px; height: 72px; }
}

@media (prefers-reduced-motion: reduce) {
  /* `auto-rotate` is an attribute, not a style, so no rule here can switch it
     off -- the page's script removes it when the visitor has asked for reduced
     motion.  These cover the two transitions this stylesheet would otherwise
     inherit. */
  .viewer-3d model-viewer { transition: none; }
  .tabs-3d button { transition: none; }
}
