/**
 * Every style the front end renders.
 *
 * A stylesheet rather than a string the bundle injects on boot: the plugin emits
 * layout — a full-height viewer, a ruled control panel, a centred information
 * block below the columns — and layout that arrives with the script arrives
 * after the first paint. The page then reflows under the reader, which is the
 * one thing a stylesheet exists to prevent. @see Arctica3D\Assets
 *
 * Loaded on both sides: the design screen and the production document mount the
 * same viewer as the storefront.
 */

.arctica-3d-viewer {
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  max-width: 100%;
  background: #f5f5f5;
  border-radius: 4px;
}
/*
 * Out of flow, and deliberately.
 *
 * Three.js sizes its canvas in pixels from the box it was measured in. In normal
 * flow that fixed pixel width becomes the intrinsic minimum of every ancestor up
 * to the nearest one that can ignore it — so a column that has held a canvas can
 * never be laid out narrower than the last width it was measured at, and the
 * next reflow that wants it narrower (a scrollbar appearing, a window resize)
 * pushes the page wider than the viewport instead. Positioned, it contributes no
 * intrinsic width at all and the wrapper alone decides the size.
 */
.arctica-3d-viewer canvas {
  position: absolute;
  inset: 0;
  cursor: grab;
}
.arctica-3d-viewer canvas:active { cursor: grabbing; }
.arctica-3d-viewer .arctica-3d-spinner {
  position: absolute; inset: 0; margin: auto;
  width: 36px; height: 36px; border-radius: 50%;
  border: 3px solid rgba(128,128,128,.25); border-top-color: rgba(128,128,128,.85);
  animation: arctica-3d-spin .8s linear infinite;
}
@keyframes arctica-3d-spin { to { transform: rotate(360deg); } }
.arctica-3d-viewer .arctica-3d-error {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: .85em; opacity: .6;
}
.arctica-3d-overlay { position: absolute; inset: 0; pointer-events: none;
  visibility: hidden; opacity: 0; transition: opacity .4s; }
.arctica-3d-overlay.is-ready { visibility: visible; opacity: 1; }
.arctica-3d-overlay svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.arctica-3d-leader { stroke: rgba(25,25,25,.55); stroke-width: 1.5; opacity: 0;
  transition: opacity .2s; }
.arctica-3d-leader.is-open { opacity: 1; }
.arctica-3d-dot {
  position: absolute; top: 0; left: 0; pointer-events: auto; cursor: pointer; z-index: 1;
  width: 20px; height: 20px; border-radius: 50%; border: none; padding: 0;
  background: rgba(25,25,25,.55);
  box-shadow: 0 0 10px rgba(255,255,255,.4);
  transition: opacity .25s;
}
.arctica-3d-dot::before {
  content: ''; position: absolute; inset: -7px; border-radius: 50%; z-index: -1;
  background: rgba(25,25,25,.22);
  box-shadow: 0 0 12px rgba(255,255,255,.3);
  animation: arctica-3d-pulse 2.2s ease-in-out infinite;
  transition: transform .2s;
}
.arctica-3d-dot:hover::before, .arctica-3d-dot.is-active::before {
  animation: none; transform: scale(1.35);
}
.arctica-3d-dot.is-hidden { opacity: .15; pointer-events: none; }
@keyframes arctica-3d-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.18); }
}
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-dot::before { animation: none; }
}
.arctica-3d-prompt {
  /* Bottom inset lifts the glyph off dead centre, which on a full-body model
     lands somewhere unfortunate. */
  position: absolute; inset: 0 0 20% 0; z-index: 2; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  color: #fff; filter: drop-shadow(0 1px 3px rgba(0,0,0,.45));
  opacity: 0; visibility: hidden; transition: opacity .4s;
}
.arctica-3d-prompt.is-visible { opacity: 1; visibility: visible; }
.arctica-3d-prompt svg {
  display: block; animation: arctica-3d-swipe 12s ease-in-out infinite;
}
/* One ~4.5s swipe, then the rest of the cycle held at zero opacity. The
   percentages carry the swipe's own pace, so lengthening the animation to
   widen the gap means shrinking them by the same factor. */
@keyframes arctica-3d-swipe {
  0%   { transform: translateX(0);     opacity: 0; }
  4%   { transform: translateX(0);     opacity: 1; }
  15%  { transform: translateX(16px);  opacity: 1; }
  28%  { transform: translateX(-16px); opacity: 1; }
  35%  { transform: translateX(0);     opacity: 1; }
  39%  { transform: translateX(0);     opacity: 0; }
  100% { transform: translateX(0);     opacity: 0; }
}
/* Must follow the rule above: the base display would otherwise win on order. */
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-prompt { display: none; }
}
.arctica-3d-card {
  position: absolute; top: 0; left: 0; pointer-events: auto; z-index: 3;
  max-width: 260px; padding: 12px 30px 12px 14px; border-radius: 10px;
  /* Near-solid rather than frosted: a blur behind a card over a turning model
     has to be worked out again on every frame. */
  background: rgba(255,255,255,.92);
  border: none; color: #1a1a1a;
  box-shadow: 0 4px 18px rgba(0,0,0,.18);
  opacity: 0; visibility: hidden; transition: opacity .2s;
}
.arctica-3d-card.is-open { opacity: 1; visibility: visible; }
.arctica-3d-card-title { font: 600 14px/1.3 system-ui, sans-serif; margin-bottom: 4px; }
.arctica-3d-card-text { font: 400 12.5px/1.45 system-ui, sans-serif; opacity: .85; }
.arctica-3d-card-close {
  position: absolute; top: 4px; right: 6px; border: none; background: none;
  font-size: 18px; line-height: 1; cursor: pointer; color: inherit; opacity: .5; padding: 4px;
}
.arctica-3d-card-close:hover, .arctica-3d-card-close:focus, .arctica-3d-card-close:active {
  background: none !important; color: inherit !important;
  border: none !important; box-shadow: none !important; opacity: 1;
}
@media (max-width: 600px) {
  .arctica-3d-card { max-width: 190px; padding: 9px 24px 9px 11px; }
  .arctica-3d-card-title { font-size: 13px; }
  .arctica-3d-card-text { font-size: 11.5px; }
}
.arctica-3d-playpause {
  position: absolute; right: 12px; bottom: 12px; z-index: 2;
  width: 36px; height: 36px; border: none; border-radius: 8px;
  background: #fff; color: #1a1a1a; cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 6px rgba(0,0,0,.15);
}
/* display:flex above outranks the UA stylesheet's [hidden] rule, so hiding the
   button needs saying explicitly. */
.arctica-3d-playpause[hidden] { display: none; }
.arctica-3d-playpause:hover, .arctica-3d-playpause:focus, .arctica-3d-playpause:active {
  background: #fff !important; color: #1a1a1a !important;
  border: none !important; box-shadow: 0 2px 8px rgba(0,0,0,.22) !important;
}
.arctica-3d-playpause svg { display: block; }
/* WooCommerce product page wrapper. Carries no width or gutter of its own —
   themes place this region differently; add a theme class server-side. */
.arctica-3d-product { position: relative; margin: 4rem 0; }
.arctica-3d-product--hidden { display: none; }
/* Customize, over the viewer's top right, wearing the rotation control's face.
   Marked with the spectrum the editor's custom color swatch wears, which is
   what the link leads to, and with what customizing starts at under its name. */
.arctica-3d-product-edit {
  position: absolute; right: 12px; top: 12px; z-index: 2;
  box-sizing: border-box; min-height: 36px; padding: 8px 14px 8px 12px; border-radius: 8px;
  display: inline-flex; align-items: center; gap: 8px;
  background: #fff; color: #000 !important; text-decoration: none;
  font: 600 14px/1 system-ui, sans-serif;
  box-shadow: 0 1px 6px rgba(0,0,0,.15);
}
.arctica-3d-product-edit::before {
  content: ''; flex: 0 0 auto;
  width: 14px; height: 14px; border-radius: 50%;
  background: conic-gradient(#e5484d, #f5a524, #46a758, #3e9dd8, #8e4ec6, #e5484d);
}
.arctica-3d-product-edit[hidden] { display: none; }
.arctica-3d-product-edit-text { display: flex; flex-direction: column; gap: 4px; }
.arctica-3d-product-edit-price { font: 400 11px/1 system-ui, sans-serif; color: #666 !important; }
.arctica-3d-product-edit-price[hidden] { display: none; }
.arctica-3d-product-edit:hover, .arctica-3d-product-edit:focus, .arctica-3d-product-edit:active {
  background: #fff !important; color: #000 !important; text-decoration: none !important;
  box-shadow: 0 2px 8px rgba(0,0,0,.22) !important;
}
.arctica-3d-variants {
  position: absolute; top: 12px; left: 12px; z-index: 2;
  display: flex; gap: 6px;
}
.arctica-3d-variant {
  width: 28px; height: 28px; padding: 0; border: none; border-radius: 6px;
  background: #fff; color: #1a1a1a; cursor: pointer; opacity: .6;
  font: 600 12px/1 system-ui, sans-serif;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 6px rgba(0,0,0,.15);
  transition: opacity .15s;
}
.arctica-3d-variant:hover, .arctica-3d-variant:focus, .arctica-3d-variant:active {
  background: #fff !important; color: #1a1a1a !important;
  border: none !important; opacity: 1;
}
.arctica-3d-variant.is-active {
  opacity: 1; box-shadow: 0 0 0 2px #1a1a1a, 0 1px 6px rgba(0,0,0,.15) !important;
}
/* Keep the authoring badge clear of the variant row when both are on. */
.arctica-3d-variants ~ .arctica-3d-picker-badge { top: 50px; }
.arctica-3d-picker-badge {
  position: absolute; top: 8px; left: 8px; z-index: 2;
  padding: 6px 10px; border-radius: 6px;
  background: rgba(20,20,20,.85); color: #fff;
  font: 500 12px/1.3 system-ui, sans-serif; pointer-events: none;
}
/* Customizer. Both wrappers are emitted server-side, into whichever region
   of the product page each belongs to — the viewer in the media column, the
   panel by the add-to-cart form — so neither carries a width or a position of
   its own. The panel is filled in by the front end. */
.arctica-3d-customizer { position: relative; }
/*
 * The editor is the page, so it takes the window rather than a fixed box: this
 * is the one viewer a shopper works in for minutes at a time, and a graphic is
 * judged at the size it is shown at. The offset is the site header plus room to
 * read the summary column beside it; 620px is the height this used to be fixed
 * at and is now the floor, for a short window or a laptop in landscape.
 *
 * Ordered so the fallback wins where dvh is unknown: an unsupported height
 * declaration is dropped, leaving min-height to size the box on its own.
 * Capped, because past about 1000px the model is no longer any easier to read and
 * the controls beside it have scrolled away.
 */
.arctica-3d-customizer .arctica-3d-viewer {
  min-height: 620px;
  height: min(calc(100dvh - var(--arctica-3d-viewer-offset, 8rem)), 1040px);
}
/* Ruled, not boxed: horizontal rules only, and the rows run the full width of
   whatever column the theme puts them in. A bordered card with its own gutter
   would be a second frame inside the summary column, indented away from the price
   and the add-to-cart button it belongs with. */
/* The page's own type, for the labels that stand beside the theme's. Named once
   here, since the panel's own text is system-ui and inheriting is not an option. */
:root {
  --arctica-3d-label-font: 'Public Sans', system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
}
.arctica-3d-panel {
  box-sizing: border-box;
  /* The size picker follows, and it is read as the next section of this list, so
     the gap to its label is the gap above any other section's. */
  margin: 0 0 14px;
  font: 400 14px/1.45 system-ui, sans-serif;
  border-top: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3;
}
/* Accordion rows, one per editable thing. Dividers between rows rather than
   around each, so the panel reads as one list. */
.arctica-3d-row:not([hidden]) ~ .arctica-3d-row { border-top: 1px solid #e3e3e3; }
/* The section labels — a row's name, the Graphics heading, and the theme's own
   size label under the panel — are one label, so they are one declaration: the
   theme's type at the weight its picker label uses. */
.arctica-3d-rowhead, .arctica-3d-graphics-head {
  color: #666;
  font: 500 16px/1.375 var(--arctica-3d-label-font);
}
.arctica-3d-rowhead {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 14px 0; border: none; cursor: pointer; text-align: left;
  background: none;
}
/* Underline rather than a filled band: with no horizontal padding a background
   would run edge to edge and read as a selected row, which the open one already
   says with its chevron and its weight. */
.arctica-3d-rowhead:hover, .arctica-3d-rowhead:focus {
  background: none !important; color: #666 !important;
  border: none !important; text-decoration: underline;
}
/* Open says itself with the chevron, so the label does not change with it. */
.arctica-3d-rowhead.is-open {
  background: none !important; color: #666 !important;
  text-decoration: none;
}
.arctica-3d-rowlabel { flex: 1 1 auto; }
/* The picture before a row's name. Its negative margins take it into the row's
   padding, so a row with a picture is as tall as one without. */
.arctica-3d-rowshot { flex: 0 0 auto; width: 36px; height: 36px; margin: -8px 0; }
.arctica-3d-rowshot img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* After the name: a required mark, drawn in its chosen color, or a logo, or a
   swatch per chosen color on the base's row. In the row's padding like the picture
   before the name, and absent on a row with nothing to show. The faint edge keeps a white mark visible on the white
   rail; it is on the box rather than the mark because a filter applies before
   the mark's mask would. */
.arctica-3d-rowpick {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; margin: -8px 0;
  filter: drop-shadow(0 0 1px rgba(0,0,0,.4));
}
.arctica-3d-rowpick:empty, .arctica-3d-rowcolors:empty { display: none; }
.arctica-3d-rowpick img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
.arctica-3d-rowcolors { flex: 0 0 auto; display: flex; gap: 3px; }
.arctica-3d-rowcolor {
  box-sizing: border-box; width: 12px; height: 12px; border-radius: 50%;
  border: 1px solid rgba(0,0,0,.15);
  background: var(--arctica-3d-rowcolor, #fff);
}
/* Chevron drawn from borders so the row needs no icon font and no inline SVG per
   row. Rotates a quarter turn on open. */
.arctica-3d-chev {
  flex: 0 0 auto; width: 7px; height: 7px; margin-right: 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform .2s; opacity: .55;
}
.arctica-3d-rowhead.is-open .arctica-3d-chev { transform: rotate(45deg); opacity: .8; }
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-chev { transition: none; }
}
.arctica-3d-panel-body { padding: 2px 0 18px; }
/* Sliding open or shut, as the base's colors do. Border box so the height being
   animated includes the padding, which slides away with it. @see
   src/customizer/Customizer.ts slide */
.arctica-3d-panel-body.is-sliding { box-sizing: border-box; overflow: hidden; }
/* Loading: the panel as the server lays it out before the script has built it,
   and a picture, a color or a measurement that has not arrived yet. A band of
   light runs across the space it will take. @see Customizer::panel_placeholder() */
.arctica-3d-skeleton { pointer-events: none; user-select: none; }
.arctica-3d-rowshot.is-loading,
.arctica-3d-rowcolor.is-loading,
.arctica-3d-swatch.is-loading,
.arctica-3d-base-shot.is-loading,
.arctica-3d-tile-pick.is-loading,
.arctica-3d-logo-preview.is-loading,
.arctica-3d-logo-file-px.is-loading,
.arctica-3d-flag-pic.is-loading {
  border-color: transparent;
  background: linear-gradient(90deg, #ececec 25%, #f7f7f7 50%, #ececec 75%) 0 0 / 200% 100%;
  animation: arctica-3d-shimmer 1.2s linear infinite;
}
.arctica-3d-rowshot.is-loading { border-radius: 3px; }
/* The drop shadow would draw an edge around the band. */
.arctica-3d-tile-pick.is-loading { filter: none; }
@keyframes arctica-3d-shimmer {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-rowshot.is-loading,
  .arctica-3d-rowcolor.is-loading,
  .arctica-3d-swatch.is-loading,
  .arctica-3d-base-shot.is-loading,
  .arctica-3d-tile-pick.is-loading,
  .arctica-3d-logo-preview.is-loading,
  .arctica-3d-logo-file-px.is-loading,
  .arctica-3d-flag-pic.is-loading { animation: none; }
}
.arctica-3d-h {
  margin: 0 0 8px; font: 700 12px/1.2 system-ui, sans-serif; color: #777;
}
.arctica-3d-h + * { margin-bottom: 18px; }
/* The bases, between the row and the colors it opens. Carries its own bottom
   margin, so it neither butts against the first color row nor sits on the
   panel's next divider while the colors are closed.
   Sized by the column like the graphic tiles, and a little wider than they are:
   a base tile carries its name under the picture, and a name has to fit. */
.arctica-3d-bases {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px;
  margin-bottom: 16px;
}
/* Same construction as a graphic tile, and square in the same way — see the note
   there for why the box sizing and the minimums are spelled out. The picture is
   the square part; the name sits under it, so the tile itself is taller.
   No padding: the picture runs to the border, and only the name is inset. */
.arctica-3d-base-tile {
  box-sizing: border-box; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: 5px;
  padding: 0; border: 1px solid #ddd; border-radius: 5px;
  background: #fff; color: #333; cursor: pointer;
  font: 500 11.5px/1.25 system-ui, sans-serif; text-align: center;
}
.arctica-3d-base-tile:hover, .arctica-3d-base-tile:focus, .arctica-3d-base-tile:active {
  background: #fff !important; color: #111 !important; border-color: #999 !important;
}
/* Outlined rather than filled. The tile's face is the picture of the base, and a
   chosen tile that paints over it answers "which one is selected" by hiding the
   thing that was selected. */
.arctica-3d-base-tile.is-active { border-color: #1a1a1a !important; box-shadow: 0 0 0 1px #1a1a1a; }
.arctica-3d-base-tile.is-active:hover,
.arctica-3d-base-tile.is-active:focus,
.arctica-3d-base-tile.is-active:active { border-color: #1a1a1a !important; }
/* Holds its square whether or not there is a picture in it, so a template part
   way through being authored has an even grid rather than a ragged one. Rounded
   to the inside of the tile's border, which it touches. */
.arctica-3d-base-shot {
  display: block; aspect-ratio: 1; overflow: hidden;
  border-radius: 4px;
}
.arctica-3d-base-shot img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Long names break inside the word rather than widening the column, which would
   pull every other tile in the row out of shape. Held off the border by the space
   the tile's own padding used to give it. */
.arctica-3d-base-name { display: block; padding: 0 5px 5px; overflow-wrap: anywhere; }
/* Required marks and logos, as tiles under the base's row, with Add Graphic last.
   Sized by the column like the base chooser, with the same tile.

   Headed like a row, since the tiles carry no names: the heading is what says
   what the grid is, and it reads as the next thing in the list after Base. */
.arctica-3d-graphics { padding: 14px 0 16px; border-top: 1px solid #e3e3e3; }
/* Typed with the row above it; only its spacing is its own. Laid out like the row
   labels too, so a badge on its right lines up with their chevrons. */
.arctica-3d-graphics-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 4px 10px; margin: 0 0 10px;
}
/* A quiet grey pill: a note about what the tiles cost, not a second heading. Set
   on the heading's own baseline so the two read as one line. Kept to one line of
   its own so that a badge too long for the rail drops under the heading rather
   than breaking mid-phrase. */
.arctica-3d-graphics-badge {
  padding: 3px 10px; border-radius: 999px; background: #eee; color: #666;
  font-size: 12px; font-weight: 500; white-space: nowrap;
}
.arctica-3d-tiles {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px;
}
/* Four across in the desktop rail, whether or not it is scrolling. The rail is
   400px with 20px of padding, which is exactly four 84px tiles and their gaps, so
   a scrollbar appearing — when the base's colors open, say — would otherwise
   drop both grids to three. */
@media (min-width: 901px) {
  .arctica-3d-app__rail .arctica-3d-tiles,
  .arctica-3d-app__rail .arctica-3d-bases { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.arctica-3d-tilecell { position: relative; min-width: 0; }
.arctica-3d-tilecell > .arctica-3d-tile { width: 100%; height: 100%; }
.arctica-3d-tile, .arctica-3d-addlogo { position: relative; }
/* Selected: outlined as a chosen base is. */
.arctica-3d-tile.is-selected,
.arctica-3d-tile.is-selected:hover,
.arctica-3d-tile.is-selected:focus,
.arctica-3d-tile.is-selected:active { border-color: #1a1a1a !important; box-shadow: 0 0 0 1px #1a1a1a; }
/* What a logo adds to the price, in the picture's top left corner, leaving the
   right one to the dot of a graphic whose colors change. */
.arctica-3d-tile-price {
  position: absolute; top: 4px; left: 4px;
  padding: 1px 5px; border-radius: 3px;
  background: rgba(255,255,255,.92); color: #333;
  font: 600 10.5px/1.4 system-ui, sans-serif; pointer-events: none;
}
.arctica-3d-tile-price:empty { display: none; }
/* A mark or a preset whose color the shopper can change, in the top right
   corner. A spectrum rather than a single swatch: one color there would read as
   the color this graphic comes in, and the graphic is already showing a color of
   its own. */
.arctica-3d-tile.is-variable::after,
.arctica-3d-preset.is-variable::after {
  content: ''; position: absolute; right: 4px; top: 4px;
  width: 11px; height: 11px; border-radius: 50%; pointer-events: none;
  background: conic-gradient(#e5484d, #f5a524, #46a758, #3e9dd8, #8e4ec6, #e5484d);
  box-shadow: 0 0 0 1.5px #fff, 0 0 2px rgba(0,0,0,.35);
}
/* Edit, and Remove on a logo, on a bar over the selected tile's picture, along
   its lower edge, just inside the border. A press between the buttons goes
   through the bar to the tile, and so does a press on the buttons while they are
   arming. @see Customizer.arm */
.arctica-3d-tile-actions {
  position: absolute; left: 1px; right: 1px; bottom: 1px;
  display: flex; justify-content: center; gap: 2px; padding: 2px 0;
  border-radius: 0 0 4px 4px; background: rgba(255,255,255,.92);
  pointer-events: none;
}
.arctica-3d-tile-actions[hidden] { display: none; }
.arctica-3d-iconbtn.arctica-3d-tile-action { width: 30px; height: 30px; color: #333; pointer-events: auto; }
.arctica-3d-tile-actions.is-arming .arctica-3d-tile-action { pointer-events: none; }
/* The mark in its color, or the logo. The faint edge keeps a white mark visible;
   it is on this box rather than the mark because a filter applies before the
   mark's mask would. */
.arctica-3d-tile-pick {
  box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; padding: 6px;
  filter: drop-shadow(0 0 1px rgba(0,0,0,.4));
}
.arctica-3d-choice {
  padding: 7px 12px; border: 1px solid #ddd; border-radius: 5px; cursor: pointer;
  background: #fff; color: #333; font: 500 12.5px/1.2 system-ui, sans-serif;
}
/*
 * Every control the panel emits states its own hover, focus and active
 * appearance, and states it importantly.
 *
 * These are <button> elements inside theme content, so a theme's global button
 * rules reach them — and a global rule that fills a button on hover fills a
 * color swatch and a graphic tile with the theme's grey, painting over the one
 * thing the control exists to show. A control whose appearance is its meaning
 * cannot leave that appearance to whatever stylesheet loads after this one, so
 * the border is what moves on hover here and the face never does.
 */
.arctica-3d-choice:hover, .arctica-3d-choice:focus, .arctica-3d-choice:active {
  background: #fff !important; color: #111 !important; border-color: #999 !important;
}
.arctica-3d-choice.is-active {
  border-color: #1a1a1a !important; background: #1a1a1a !important; color: #fff !important;
}
/* What the design sells as and its price on one line, then why and the way back
   to the original. Above add-to-cart on the immersive page, heading the panel
   elsewhere. */
.arctica-3d-tierrow {
  padding: 12px 0;
  font: 400 13px/1.4 system-ui, sans-serif; color: #555;
}
.arctica-3d-tierrow.is-pinned { padding: 0 0 12px; }
/* The tier's name, its info button beside it, and the price flush right. */
.arctica-3d-tier-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px;
  font-size: 15px; color: #111;
}
.arctica-3d-tier-label { font-weight: 600; }
.arctica-3d-tier-price { margin-left: auto; font-weight: 600; }
.arctica-3d-tier-price del { font-weight: 400; color: #777; margin-right: 4px; }
.arctica-3d-tier-price ins { text-decoration: none; }
.arctica-3d-tier-why { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; margin-top: 2px; }
/* The info button on the tier line: centered on the line rather than on its
   baseline, and a 26px target on a line of text. */
.arctica-3d-tier-head .arctica-3d-tier-info { align-self: center; margin: -4px 0 -4px -2px; }
/* The pricing dialog's tiers. */
.arctica-3d-tierlist { margin: 4px 0 12px; }
.arctica-3d-tierlist-item { padding: 10px 0; border-top: 1px solid #eee; }
.arctica-3d-tierlist-item:first-child { border-top: none; padding-top: 4px; }
.arctica-3d-tierlist-text { margin: 2px 0 0; font-size: 13px; color: #555; }.arctica-3d-region { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.arctica-3d-region-label { flex: 0 0 88px; font-size: 13px; color: #333; }
.arctica-3d-swatches { display: flex; flex-wrap: wrap; gap: 5px; min-width: 0; }
/*
 * The color arrives as a custom property rather than as an inline background,
 * so that the important rules below can restate it. An inline declaration loses
 * to a theme's `!important` hover fill; a property the plugin's own important
 * rule reads cannot be overwritten by a stylesheet that knows nothing about it.
 */
.arctica-3d-swatch {
  width: 26px; height: 26px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(0,0,0,.15);
  background: var(--arctica-3d-swatch, #fff);
}
.arctica-3d-swatch:hover, .arctica-3d-swatch:focus, .arctica-3d-swatch:active {
  background: var(--arctica-3d-swatch, #fff) !important;
  border-color: rgba(0,0,0,.45) !important;
}
.arctica-3d-swatch.is-active {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px #1a1a1a !important;
}
/* Split down the middle into the two inks it chooses between — the design's
   own, so the swatch shows the colors the shopper will actually get rather
   than a stand-in pair. Says what it does without a caption and without an icon
   to keep in step.
   Sized against the border box rather than the padding box the shorthand would
   default it to: the swatch has a border, so a gradient sized inside it is
   narrower than the area it is painted over and wraps its far edge onto its
   near one — a sliver of each color on the wrong side of the split. */
.arctica-3d-swatch-auto,
.arctica-3d-swatch-auto:hover,
.arctica-3d-swatch-auto:focus,
.arctica-3d-swatch-auto:active {
  background: linear-gradient(
    90deg,
    var(--arctica-3d-auto-dark, #1a1a1a) 0 50%,
    var(--arctica-3d-auto-light, #fff) 50% 100%
  ) !important;
  background-origin: border-box !important;
  background-repeat: no-repeat !important;
}
/* The swatch that opens the picker, last in the row: the spectrum a graphic
   tile shows for a color that changes. While it is the selection, the color
   inside a spectrum ring. Sized against the border box, as the automatic
   swatch is. */
.arctica-3d-swatch-custom,
.arctica-3d-swatch-custom:hover,
.arctica-3d-swatch-custom:focus,
.arctica-3d-swatch-custom:active {
  background: conic-gradient(#e5484d, #f5a524, #46a758, #3e9dd8, #8e4ec6, #e5484d) border-box !important;
}
.arctica-3d-swatch-custom.is-custom,
.arctica-3d-swatch-custom.is-custom:hover,
.arctica-3d-swatch-custom.is-custom:focus,
.arctica-3d-swatch-custom.is-custom:active {
  border: 3px solid transparent !important;
  background:
    linear-gradient(var(--arctica-3d-swatch, #fff), var(--arctica-3d-swatch, #fff)) padding-box,
    conic-gradient(#e5484d, #f5a524, #46a758, #3e9dd8, #8e4ec6, #e5484d) border-box !important;
}
/* The picker, under the row whose color it sets. */
.arctica-3d-picker {
  margin: 0 0 12px; padding: 10px 12px 2px;
  border: 1px solid #e3e3e3; border-radius: 6px;
}
.arctica-3d-picker .arctica-3d-logo-key { flex-basis: 76px; }
/* A slider whose track shows its range, and whose thumb is the color chosen. */
.arctica-3d-slider {
  flex: 1 1 auto; box-sizing: border-box; min-width: 0; height: 34px; margin: 0; padding: 0;
  border: none; background: transparent; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
/* Over the theme's `input:focus`, which draws a border round the whole slider. */
.arctica-3d-slider:focus { border: none; outline: none; }
.arctica-3d-slider::-webkit-slider-runnable-track {
  height: 14px; border-radius: 7px;
  background: var(--arctica-3d-track); box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
}
.arctica-3d-slider::-moz-range-track {
  height: 14px; border-radius: 7px;
  background: var(--arctica-3d-track); box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
}
.arctica-3d-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  box-sizing: border-box; width: 24px; height: 24px; margin-top: -5px;
  border: 3px solid #fff; border-radius: 50%;
  background: var(--arctica-3d-thumb, #fff);
  box-shadow: 0 0 0 1px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.25);
}
.arctica-3d-slider::-moz-range-thumb {
  box-sizing: border-box; width: 24px; height: 24px;
  border: 3px solid #fff; border-radius: 50%;
  background: var(--arctica-3d-thumb, #fff);
  box-shadow: 0 0 0 1px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.25);
}
.arctica-3d-slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px #111, 0 1px 3px rgba(0,0,0,.25); }
.arctica-3d-slider:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px #111, 0 1px 3px rgba(0,0,0,.25); }
.arctica-3d-textinput.arctica-3d-hexinput { flex: 0 1 120px; }
/* The Add Graphic dialog's earlier uploads and presets. Sized by the column
   rather than by a column count: a fixed count turns into 140px tiles in a wide
   dialog and cramped ones in a narrow one. */
.arctica-3d-presets {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 6px;
  /* Carries its own spacing: the row has no heading above it any more, so the
     rule that used to space it from the next control no longer applies. */
  margin-bottom: 10px;
}
/*
 * Square, and held square against the theme.
 *
 * `aspect-ratio` sizes whichever box `box-sizing` names, so a theme that leaves
 * buttons on `content-box` adds the padding and the border on top and the tile
 * comes out taller than it is wide. The minimums are the other way a theme
 * breaks it: a touch-target floor like `button { min-height: 44px }` applies at
 * a phone breakpoint and nowhere else, which is exactly the shape of a tile that
 * is square on a desktop and not on a phone.
 */
.arctica-3d-preset {
  position: relative;
  box-sizing: border-box;
  aspect-ratio: 1; min-width: 0; min-height: 0;
  padding: 5px; border: 1px solid #ddd; border-radius: 5px;
  background: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.arctica-3d-preset:hover, .arctica-3d-preset:focus, .arctica-3d-preset:active {
  background: #fff !important; border-color: #999 !important; box-shadow: none;
}
.arctica-3d-preset img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* Text, after the flags: "Aa" and a text cursor in the dialog's ink rather than
   words in any one font. Held against the theme's own hover and focus colors. */
.arctica-3d-preset-text,
.arctica-3d-preset-text:hover,
.arctica-3d-preset-text:focus,
.arctica-3d-preset-text:active { color: #1a1a1a !important; }
.arctica-3d-preset-text svg { display: block; width: 70%; height: 70%; }
/*
 * The flags, first among the presets, as a folder rather than a tile: the button
 * has no box of its own, and its shape is a tab over a body, in the tiles' border
 * and corners on a grey that sets it apart from the white files beside it. The
 * tab overlaps the body by its border and is the same grey, so the line under it
 * is covered and the two read as one outline. Held against the theme's buttons.
 */
.arctica-3d-folder,
.arctica-3d-folder:hover,
.arctica-3d-folder:focus,
.arctica-3d-folder:active {
  box-sizing: border-box; display: flex; flex-direction: column;
  aspect-ratio: 1; min-width: 0; min-height: 0; margin: 0; padding: 0;
  border: none !important; border-radius: 0; background: none !important; box-shadow: none !important;
  color: #333 !important; cursor: pointer;
}
.arctica-3d-folder:focus-visible { outline: 2px solid #444; outline-offset: 2px; }
.arctica-3d-folder-tab {
  position: relative; z-index: 1; flex: none; align-self: flex-start;
  box-sizing: border-box; width: 46%; height: 9px; margin-bottom: -1px;
  border: 1px solid #ddd; border-bottom: none; border-radius: 5px 5px 0 0;
  background: #f5f5f5;
}
.arctica-3d-folder-body {
  flex: 1 1 auto; min-height: 0; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  border: 1px solid #ddd; border-radius: 0 5px 5px 5px; background: #f5f5f5;
}
.arctica-3d-folder:hover .arctica-3d-folder-tab,
.arctica-3d-folder:hover .arctica-3d-folder-body,
.arctica-3d-folder:focus .arctica-3d-folder-tab,
.arctica-3d-folder:focus .arctica-3d-folder-body { border-color: #999; }
.arctica-3d-folder-body svg { display: block; flex: none; color: #555; }
.arctica-3d-folder-name { font: 600 11.5px/1.2 system-ui, sans-serif; color: #333; }
/*
 * The flags, in the Add Graphic dialog. Each flag is its small copy over its
 * name, since flags alike in their colors are told apart by the name. The way
 * back sits above the title, as plain text with a chevron.
 */
.arctica-3d-dialog-back,
.arctica-3d-dialog-back:hover,
.arctica-3d-dialog-back:focus,
.arctica-3d-dialog-back:active {
  display: inline-flex; align-items: center; gap: 2px; margin: -4px 0 6px -4px; padding: 2px 4px 2px 0;
  border: none !important; background: none !important; box-shadow: none !important;
  color: #555 !important; font: 400 13px/1.2 system-ui, sans-serif; cursor: pointer;
}
.arctica-3d-dialog-back:hover { color: #111 !important; }
.arctica-3d-dialog-back svg { flex: none; }
.arctica-3d-textinput.arctica-3d-flag-search { display: block; width: 100%; margin: 0 0 12px; }
.arctica-3d-flags {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 6px;
  margin-bottom: 12px;
}
.arctica-3d-flag,
.arctica-3d-flag:hover,
.arctica-3d-flag:focus,
.arctica-3d-flag:active {
  box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 6px;
  min-width: 0; min-height: 0; margin: 0; padding: 8px 4px 6px;
  border: 1px solid #ddd; border-radius: 5px; background: #fff !important; box-shadow: none;
  color: #333 !important; cursor: pointer;
}
.arctica-3d-flag:hover, .arctica-3d-flag:focus { border-color: #999 !important; }
/* A fixed box, so a row of flags of different shapes lines its names up. */
.arctica-3d-flag-pic {
  display: flex; align-items: center; justify-content: center;
  width: 64px; height: 48px; border-radius: 2px;
}
.arctica-3d-flag-pic img {
  display: block; max-width: 100%; max-height: 100%; object-fit: contain;
  box-shadow: 0 0 0 1px rgba(0,0,0,.08);
}
.arctica-3d-flag-name {
  max-width: 100%; font: 400 11.5px/1.25 system-ui, sans-serif; text-align: center;
  overflow-wrap: anywhere;
}
.arctica-3d-flag-folders { border-top: 1px solid #eee; }
.arctica-3d-flag-folder,
.arctica-3d-flag-folder:hover,
.arctica-3d-flag-folder:focus,
.arctica-3d-flag-folder:active {
  box-sizing: border-box; display: flex; align-items: center; gap: 8px; width: 100%;
  min-height: 0; margin: 0; padding: 12px 2px; text-align: left;
  border: none !important; border-bottom: 1px solid #eee !important; border-radius: 0;
  background: none !important; box-shadow: none !important;
  color: #111 !important; font: 400 14px/1.3 system-ui, sans-serif; cursor: pointer;
}
.arctica-3d-flag-folder-name { flex: 1 1 auto; min-width: 0; }
.arctica-3d-flag-folder-count { flex: none; color: #888; font-variant-numeric: tabular-nums; }
.arctica-3d-flag-folder svg { flex: none; color: #888; }
/*
 * A recolorable required mark, drawn in the color chosen for it. The artwork is
 * authored white, so the picture shows its alpha filled rather than the file
 * itself — a white mark on a white row is a picture with nothing on it, and a
 * grey background light enough to match the viewer behind the model is not
 * enough contrast to fix that.
 *
 * The <img> inside is the fallback: without mask compositing it is simply the
 * artwork, as drawn. It costs no second request, being the same URL the mask is.
 */
.arctica-3d-shape {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; align-self: stretch;
}
@supports (mask-image: url(#m)) or (-webkit-mask-image: url(#m)) {
  .arctica-3d-shape {
    background-color: var(--arctica-3d-ink, #1a1a1a);
    -webkit-mask: var(--arctica-3d-shape) center / contain no-repeat;
    mask: var(--arctica-3d-shape) center / contain no-repeat;
  }
  .arctica-3d-shape img { visibility: hidden; }
}
.arctica-3d-add, .arctica-3d-add:hover, .arctica-3d-add:focus, .arctica-3d-add:active {
  border-style: dashed; border-color: #b4b4b8 !important;
}
.arctica-3d-add-mark { font-size: 22px; line-height: 1; color: #6b6b70; }
/* Add Graphic: the `+` mark centered in a tile's picture square, with the name
   under it inside the square, centered too where it wraps. */
.arctica-3d-base-tile.arctica-3d-add .arctica-3d-base-shot {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
}
.arctica-3d-add-name { font-size: 11.5px; line-height: 1.2; color: #555; text-align: center; }
/* At the most logos a design may carry. */
.arctica-3d-base-tile:disabled { opacity: .45; cursor: default; }
/*
 * Hidden, and importantly.
 *
 * This is an <input type="file"> in theme content, so a theme that gives file
 * inputs a size or an opacity of their own puts the browser's own "No file
 * chosen" back on the page. Clipped as well as transparent, so it stays out of
 * the layout whatever wins on the box.
 */
.arctica-3d-file {
  position: absolute !important; width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important; border: 0 !important;
  overflow: hidden !important; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; opacity: 0 !important;
}
.arctica-3d-note { margin: 0 0 12px; font-size: 11.5px; color: #777; }
/*
 * The upload dialog.
 *
 * Appended to the body rather than into the panel: it is a fixed overlay, and a
 * theme's transformed or overflow-hidden container would clip it or take it out
 * of the viewport. Which also means it carries its own type — it is outside the
 * panel that would otherwise have set it.
 */
.arctica-3d-modal {
  position: fixed; inset: 0; z-index: 999999;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: rgba(20,20,20,.55);
}
.arctica-3d-dialog {
  position: relative; box-sizing: border-box;
  width: 100%; max-width: 420px; max-height: 86vh; overflow: auto;
  padding: 18px; border-radius: 8px; background: #fff; color: #333;
  font: 400 14px/1.45 system-ui, sans-serif;
  box-shadow: 0 12px 44px rgba(0,0,0,.32);
}
.arctica-3d-dialog-title {
  margin: 0 28px 8px 0; color: #111;
  font: 600 16px/1.25 system-ui, sans-serif;
}
.arctica-3d-dialog-close {
  position: absolute; top: 4px; right: 6px; border: none; background: none;
  font-size: 20px; line-height: 1; cursor: pointer; color: #555; padding: 4px;
}
.arctica-3d-dialog-close:hover, .arctica-3d-dialog-close:focus, .arctica-3d-dialog-close:active {
  background: none !important; color: #111 !important;
  border: none !important; box-shadow: none !important;
}
.arctica-3d-dialog .arctica-3d-choice { margin-bottom: 14px; }
/* The permission note under Choose a file is about that button, so it sits close. */
.arctica-3d-dialog .arctica-3d-choice + .arctica-3d-note { margin-top: -8px; }
/* Its Terms link reads as part of the small print, in its color. */
.arctica-3d-dialog .arctica-3d-note a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* A confirmation: the question, what it does, and the answers on the right. */
.arctica-3d-dialog-text { margin: 0 0 16px; color: #555; }
.arctica-3d-dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
/* A store design offered in place of the shopper's own work: its picture, clear
   of the close button, then its name and the question. */
.arctica-3d-dialog.is-offer { max-width: 340px; }
.arctica-3d-offer-thumb {
  box-sizing: border-box; width: 100%; aspect-ratio: 1; margin: 16px 0 12px;
  border: 1px solid #e3e3e3; border-radius: 6px; overflow: hidden; background: #f2f2f2;
}
.arctica-3d-offer-thumb img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  border: 0; border-radius: 0; background: none;
}
/* Last in the dialog, and the only thing under it is the dialog's own padding. */
.arctica-3d-dialog > :last-child { margin-bottom: 0; }
/* What the open logo's keys act on, laid over the model. Its outline and
   handles are drawn on the model itself. Inert to the pointer: presses reach the
   model, and the logo editor takes the ones that land on the logo. Focusable for
   the arrow, +/- and bracket keys, with the ring shown only when it was reached
   from the keyboard. Focus given by a press on the model shows none, though a
   browser shows it once a key is pressed there. */
.arctica-3d-logo-keys { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.arctica-3d-logo-keys:focus { outline: none; }
.arctica-3d-logo-keys:focus-visible:not(.is-pressed) { outline: 2px solid #444; outline-offset: -2px; }
/* What a press on the model would do. */
.arctica-3d-viewer.is-logo-move canvas,
.arctica-3d-viewer.is-logo-move canvas:active { cursor: move; }
.arctica-3d-viewer.is-logo-grip canvas,
.arctica-3d-viewer.is-logo-grip canvas:active,
.arctica-3d-viewer.is-placing canvas,
.arctica-3d-viewer.is-placing canvas:active { cursor: crosshair; }
/* The open logo: a large picture of its file with what the file is under it,
   then a line each for its size and turn. An open required mark has the same
   picture, over its name. */
.arctica-3d-logo-file { margin-bottom: 16px; }
/* The box is its own element because a mark's picture is masked, and a mask
   would take a border off with everything else outside the shape. */
.arctica-3d-logo-preview {
  box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  width: 100%; height: 200px; padding: 16px;
  border: 1px solid #e3e3e3; border-radius: 4px; background: #f5f5f5;
}
.arctica-3d-logo-preview img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  border: 0; border-radius: 0; background: none;
}
/* A preset in the shopper's colors, drawn in place of its file wherever the
   file would show. */
.arctica-3d-inked { display: block; width: 100%; height: 100%; object-fit: contain; }
.arctica-3d-logo-about { display: flex; align-items: flex-start; gap: 10px; margin-top: 8px; }
.arctica-3d-logo-facts {
  display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0;
  font-size: 12.5px; line-height: 1.45; color: #666; font-variant-numeric: tabular-nums;
}
.arctica-3d-logo-file-name {
  font-size: 13px; color: #111; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The lock and the bin, beside what the file says, at the sidebar tile's size. */
.arctica-3d-logo-actions { display: flex; flex: 0 0 auto; gap: 2px; margin: -3px -4px 0 0; }
.arctica-3d-logo-actions .arctica-3d-iconbtn { width: 30px; height: 30px; color: #333; }
/* Locked: the shut padlock, in a dark outline. Held against the theme's own
   hover and focus rules, so the state stays readable under the pointer. */
.arctica-3d-iconbtn.arctica-3d-logo-lock.is-on,
.arctica-3d-iconbtn.arctica-3d-logo-lock.is-on:hover,
.arctica-3d-iconbtn.arctica-3d-logo-lock.is-on:focus,
.arctica-3d-iconbtn.arctica-3d-logo-lock.is-on:active { border-color: #111 !important; color: #111 !important; }
/* The pixels, before the file has been measured: a bar where they will be,
   which goes once the line beside it can say them. */
.arctica-3d-logo-file-px { display: none; }
.arctica-3d-logo-file-px.is-loading { display: block; width: 72px; height: 12px; margin: 3px 0 2px; border-radius: 3px; }
.arctica-3d-logo-field { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; font-size: 13px; color: #333; }
/* Layer, while the logo overlaps no other. display:flex above outranks the UA
   stylesheet's [hidden] rule. */
.arctica-3d-logo-field[hidden] { display: none; }
.arctica-3d-logo-key { flex: 0 0 64px; }
/* Keep original colors: a name longer than the other fields' keys. */
.arctica-3d-original .arctica-3d-logo-key { flex: 0 1 auto; }
.arctica-3d-stepper { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.arctica-3d-logo-value { min-width: 52px; color: #333; text-align: center; font-variant-numeric: tabular-nums; }
/* − and +. Held, they repeat, so a long press must not select text or open the
   touch callout, and a quick second press must not zoom the page. */
.arctica-3d-iconbtn.arctica-3d-step {
  width: 34px; height: 34px; border-color: #d0d0d0; color: #333;
  touch-action: manipulation; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.arctica-3d-iconbtn.arctica-3d-step[aria-disabled="true"] { opacity: .35; cursor: default; }
/* The Repeat switch, at the end of its line where a stepper would be: a track
   with a knob, dark and to the right while on. Held against the theme's button
   colors. */
.arctica-3d-switch,
.arctica-3d-switch:hover,
.arctica-3d-switch:focus,
.arctica-3d-switch:active {
  position: relative; flex: none; box-sizing: border-box; margin: 0 0 0 auto;
  width: 40px; height: 24px; min-width: 0; min-height: 0; padding: 0;
  border: none !important; border-radius: 12px; box-shadow: none !important;
  background: #c8c8cc !important; cursor: pointer; transition: background-color .15s;
}
.arctica-3d-switch::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.3);
  transition: transform .15s;
}
.arctica-3d-switch[aria-checked="true"] { background: #111 !important; }
.arctica-3d-switch[aria-checked="true"]::after { transform: translateX(16px); }
.arctica-3d-switch:focus-visible { outline: 2px solid #444; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-switch, .arctica-3d-switch::after { transition: none; }
}
/* A text logo's words, filling the line after the label. 16px type, since
   anything smaller makes a phone zoom the page into the field. */
.arctica-3d-textinput {
  flex: 1 1 auto; box-sizing: border-box; min-width: 0; height: 34px; margin: 0;
  padding: 0 10px; border: 1px solid #d0d0d0; border-radius: 4px;
  background-color: #fff; color: #111; font: 400 16px/1.2 system-ui, sans-serif;
}
.arctica-3d-textinput:focus { border-color: #111; outline: none; }
.arctica-3d-textinput:disabled { background-color: #f5f5f5; color: #999; }
/* Its fonts, three to a line after the label, which sits level with the first
   line. Each tile says the same sample in its own font, set on the sample
   rather than on the button, which a theme's button rules reach. */
.arctica-3d-logo-field.arctica-3d-fontfield { align-items: flex-start; }
.arctica-3d-fontfield .arctica-3d-logo-key { padding-top: 11px; }
.arctica-3d-fonts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px;
  flex: 1 1 auto; min-width: 0;
}
.arctica-3d-fonttile {
  box-sizing: border-box; height: 40px; min-width: 0; min-height: 0; margin: 0; padding: 0 4px;
  border: 1px solid #d0d0d0; border-radius: 4px; background: #fff; color: #111;
  cursor: pointer; overflow: hidden;
}
.arctica-3d-fonttile:hover, .arctica-3d-fonttile:focus, .arctica-3d-fonttile:active {
  background: #fff !important; color: #111 !important; border-color: #999 !important;
}
.arctica-3d-fonttile.is-active,
.arctica-3d-fonttile.is-active:hover,
.arctica-3d-fonttile.is-active:focus {
  border-color: #111 !important; box-shadow: inset 0 0 0 1px #111;
}
.arctica-3d-fonttile:disabled { cursor: default; opacity: .5; }
.arctica-3d-fontsample {
  display: block; overflow: hidden; white-space: nowrap;
  font-family: var(--arctica-3d-font), sans-serif; font-size: 15px; font-weight: 400;
  line-height: 1; letter-spacing: normal; text-transform: none;
}
.arctica-3d-textnote:empty { display: none; }
.arctica-3d-logo-dpi { margin: 2px 0 10px; font-size: 12.5px; color: #555; }
.arctica-3d-logo-dpi:empty { display: none; }
.arctica-3d-logo-dpi.is-low { color: #b32d2e; }
/* The open view: the base's controls, or a logo's or mark's under Edit Graphic, in
   place of everything else in the rail.
   @see src/customizer/Customizer.ts buildGraphic */
.arctica-3d-graphic { box-sizing: border-box; font: 400 14px/1.45 system-ui, sans-serif; }
.arctica-3d-graphic-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 0 14px; padding: 0 0 10px; border-bottom: 1px solid #e3e3e3;
}
/* In the page's own type, as the product name is. */
.arctica-3d-graphic-title { margin: 0; color: #111; font: 700 18px/1.25 var(--arctica-3d-label-font); }
.arctica-3d-graphic-title:focus { outline: none; }
/* A 40px target with the same 24px glyph as the rail's own close. The icon
   button's hover border is taken off: this one sits in a bar, not beside a value. */
.arctica-3d-iconbtn.arctica-3d-graphic-close {
  width: 40px; height: 40px; margin: -8px -10px -8px 0;
  border: none; border-radius: 0; color: #333;
}
.arctica-3d-iconbtn.arctica-3d-graphic-close:hover,
.arctica-3d-iconbtn.arctica-3d-graphic-close:focus,
.arctica-3d-iconbtn.arctica-3d-graphic-close:active { border-color: transparent !important; }
.arctica-3d-iconbtn.arctica-3d-graphic-close:focus-visible { outline: 2px solid #444; outline-offset: -4px; }
.arctica-3d-graphic-close svg { display: block; width: 24px; height: 24px; }
/* The icon button's own display would otherwise show it. */
.arctica-3d-iconbtn.arctica-3d-graphic-close[hidden] { display: none; }
/* In the rail it is the only thing showing, and scrolls as the region it stands in
   for does. The form stays in the document, out of view. */
.arctica-3d-app__rail > .arctica-3d-graphic:not([hidden]) {
  order: 1; flex: 1 1 auto; min-height: 0;
  padding: 20px; overflow-y: auto; overscroll-behavior: contain;
}
.arctica-3d-app__rail.is-editing-graphic > .arctica-3d-app__scroll,
.arctica-3d-app__rail.is-editing-graphic > .arctica-3d-app__action { display: none; }
/* A still copy of it, laid over the list that has come back, fading out.
   @see src/customizer/Customizer.ts viewGhost */
.arctica-3d-app__rail > .arctica-3d-graphic.is-leaving {
  position: absolute; inset: 0; z-index: 1;
  background: #fff; pointer-events: none;
}
.arctica-3d-iconbtn {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; cursor: pointer;
  border: 1px solid transparent; border-radius: 4px;
  background: none; color: #666; line-height: 0;
}
.arctica-3d-iconbtn:hover, .arctica-3d-iconbtn:focus, .arctica-3d-iconbtn:active {
  background: none !important; color: #111 !important;
  border-color: #bbb !important; box-shadow: none !important;
}
/* Authoring tool (design screen, editors only). The capture layer sits inert
   above the canvas and only takes pointer events while a placement is in
   progress, so orbiting to frame a location and positioning something on it
   never fight each other. */
.arctica-3d-author-capture { position: absolute; inset: 0; z-index: 3; display: none; }
.arctica-3d-author-capture.is-armed { display: block; cursor: crosshair; }
.arctica-3d-author-hint {
  position: absolute; left: 8px; bottom: 8px; z-index: 4; display: none;
  max-width: calc(100% - 16px); padding: 7px 10px; border-radius: 6px;
  background: rgba(20,20,20,.85); color: #fff;
  font: 500 12px/1.35 system-ui, sans-serif;
}
.arctica-3d-author-hint.is-visible { display: block; }
/* Centre lines, marking the orbit target — the point the camera looks at, which
   is therefore dead centre of frame at every viewport size. Two tones so the
   lines read over both the dark model and the light background. Below the capture
   layer, and inert regardless. */
.arctica-3d-author-guides { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.arctica-3d-author-guides::before,
.arctica-3d-author-guides::after {
  content: ''; position: absolute;
  background: rgba(17, 24, 39, .35);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .35);
}
.arctica-3d-author-guides::before { top: 0; bottom: 0; left: 50%; width: 1px; }
.arctica-3d-author-guides::after { left: 0; right: 0; top: 50%; height: 1px; }
.arctica-3d-guides-off .arctica-3d-author-guides { display: none; }
/* Debug boxes: the performance overlay, and an open logo's print readouts at the
   end of Edit Graphic. */
.arctica-3d-stats, .arctica-3d-debug {
  margin: 0; padding: 7px 10px; border-radius: 6px;
  background: rgba(20,20,20,.82); color: #eaeaea;
  font: 400 11px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: pre;
}
/* Top right — the other corners are taken by the variant row, the picker badge
   and play/pause. Click to collapse to the frame rate alone, so it can be left
   running without covering the model. */
.arctica-3d-stats {
  position: absolute; top: 8px; right: 8px; z-index: 4;
  cursor: pointer; user-select: none;
}
/* Its lines can be longer than a narrow rail is wide. */
.arctica-3d-debug { margin-top: 14px; overflow-x: auto; }
.arctica-3d-stats.is-collapsed { max-height: 1.45em; overflow: hidden; }
.arctica-3d-pick-marker {
  position: absolute; top: 0; left: 0; width: 18px; height: 18px; border-radius: 50%;
  background: #ffffff; color: #1a1a1a; font: 600 11px/18px system-ui, sans-serif;
  text-align: center; pointer-events: none; box-shadow: 0 1px 4px rgba(0,0,0,.4);
}
/* ---- Saving a design ---------------------------------------------------
   One button, and the dialog it opens. On the immersive page the button sits
   over the garment with the other whole-model controls (see the stage rules
   below); anywhere else it sits under the accordion, and this is how it looks
   there: a secondary button with its words showing. */
.arctica-3d-savebtn {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 14px; padding: 7px 14px; cursor: pointer;
  border: 1px solid #1a1a1a; border-radius: 4px; background: none; color: #1a1a1a;
  font: 500 13.5px/1.2 system-ui, sans-serif;
}
.arctica-3d-savebtn[hidden] { display: none; }
.arctica-3d-savebtn svg { display: block; width: 16px; height: 16px; }
/* Unsaved changes. A dot rather than words, because it has to read on a 48px
   icon over the garment; the words are the button's label and tooltip. The
   icon's own color, as editors mark an unsaved tab: red or amber would say
   something has gone wrong, and nothing has. The white ring keeps it apart from
   the garment behind. */
.arctica-3d-savebtn.is-dirty::after {
  content: ''; position: absolute; top: 6px; right: 6px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #1a1a1a; box-shadow: 0 0 0 2px #fff;
}
.arctica-3d-saving-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* Which design Save writes to, at the top of the dialog. This line is what lets
   there be one Save button instead of two: the target is on screen, so pressing
   it is never a guess about where the work is going. */
.arctica-3d-saving-current {
  margin: 0 0 12px; font: 500 12.5px/1.35 system-ui, sans-serif; color: #555;
}
.arctica-3d-saving-label {
  display: block; margin: 0 0 4px; color: #333;
  font: 500 12.5px/1.3 system-ui, sans-serif;
}
/* The designs list, under Save and the file operations. */
.arctica-3d-saving-subtitle {
  margin: 18px 0 6px; padding-top: 14px; border-top: 1px solid #ececec; color: #111;
  font: 600 13.5px/1.3 system-ui, sans-serif;
}
/* A theme's own button rules are welcome on these two — unlike a swatch or a
   graphic tile, a Save button carries no meaning in its face, so matching the
   surrounding shop is better than overriding it. Only the layout is stated. */
.arctica-3d-save {
  padding: 9px 16px; border-radius: 4px; cursor: pointer;
  border: 1px solid #1a1a1a; background: #1a1a1a; color: #fff;
  font: 500 13.5px/1.2 system-ui, sans-serif;
}
.arctica-3d-save.is-secondary { background: none; color: #1a1a1a; }
.arctica-3d-saving-name {
  display: block; width: 100%; box-sizing: border-box;
  padding: 8px 10px; border: 1px solid #cfcfcf; border-radius: 4px;
  font: 400 14px/1.3 system-ui, sans-serif;
}
/* The same field the list renames a row with, here naming the design being
   saved, directly above the button that saves it under that name. */
.arctica-3d-saving-head .arctica-3d-saving-name { margin: 0 0 10px; }
.arctica-3d-saving-note, .arctica-3d-saving-status {
  margin: 9px 0 0; font: 400 12.5px/1.4 system-ui, sans-serif; color: #646970;
}
.arctica-3d-saving-status.is-error { color: #b32d2e; }

/* Heads the summary when a team design or an ordered design is open: whose it
   is, and the way back. */
.arctica-3d-open-note {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px;
  margin: 0 0 16px; padding: 10px 12px; border-radius: 4px;
  border: 1px solid #72aee6; background: #f0f6fc;
  color: #1d2327; font: 400 13px/1.4 system-ui, sans-serif;
}
.arctica-3d-open-note a { color: #2271b1; text-decoration: underline; text-underline-offset: 2px; }
/* A row action, drawn as the piece of text it reads as. A button because that
   is what it does — nothing here navigates anywhere. */
.arctica-3d-textbtn {
  padding: 0; border: 0; background: none; cursor: pointer;
  color: #646970; font: 400 12.5px/1.4 system-ui, sans-serif;
  text-decoration: underline; text-underline-offset: 2px;
}
/* Same reason as the row: these are buttons, so a shop's button fill would
   otherwise turn three words of small print into three colored blocks. */
.arctica-3d-textbtn:hover,
.arctica-3d-textbtn:focus,
.arctica-3d-textbtn:active {
  background: none !important; color: #1a1a1a !important;
  border: 0 !important; box-shadow: none !important;
}

/* The shopper's own designs, in a dialog rather than under the buttons. Inline,
   the list pushed the editor's own controls down the page and left that space
   empty whenever it was closed — and this is the same kind of job as the upload
   dialog it is styled after: not editing the design, done and dismissed. */
/* Wider than the upload dialog, which holds one file field. This holds a column
   of pictures with a name, a date and three actions beside each, and every one
   of those has to sit on its row without wrapping. */
.arctica-3d-dialog.is-designs { max-width: 560px; }
/* The same buttons as Save, outlined rather than filled: one kind of button in
   the dialog, with Save the only filled one. */
.arctica-3d-saving-tools { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
/* Inside the dialog the status line is a message about what just happened in it,
   so it sits under the title rather than trailing the whole list. */
.arctica-3d-dialog .arctica-3d-saving-status { margin: 0 0 12px; }
.arctica-3d-dialog .arctica-3d-saving-status:empty { display: none; }
/* The one question the editor asks, put where the thing it is about is. */
.arctica-3d-saving-confirm {
  margin-bottom: 12px; padding: 10px 12px; border-radius: 4px;
  border: 1px solid #dba617; background: #fcf9e8;
}
.arctica-3d-saving-confirm .arctica-3d-saving-note { margin: 0 0 9px; color: #4a3d0e; }

.arctica-3d-design-list { margin: 0; padding: 0; list-style: none; }
.arctica-3d-design-row {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 10px 3px 0; border-bottom: 1px solid #ececec;
}
.arctica-3d-design-row:last-child { border-bottom: 0; }
/* The highlight covers the whole row, actions included, so the row reads as one
   design. Only the picture and name open it. */
.arctica-3d-design-row:hover,
.arctica-3d-design-row:focus-within { background: #f5f5f5; }
/* Nothing marks the row Save would write to. "Editing now" is already on its
   date line, in words, and a rule down the edge was a second answer to the same
   question drawn in the one place a list of pictures has no room for one. */

/* Everything but the row actions opens the design, so the target is the whole
   tile and its text rather than a word at the end of the line. */
.arctica-3d-design-open {
  display: flex; align-items: center; gap: 10px; flex: 1 1 auto; min-width: 0;
  padding: 5px; border: 0; border-radius: 0; background: none;
  color: inherit; cursor: pointer; text-align: left;
}
/* Stated rather than left to the theme. A row is a button, so a shop's own
   button fill lands on it — which on this row means the brand color washing
   over the thumbnails, the one thing in here the shopper is choosing between.
   Transparent, because the row behind it carries the highlight. */
.arctica-3d-design-open:hover,
.arctica-3d-design-open:focus,
.arctica-3d-design-open:active {
  background: none !important; color: inherit !important;
  border: 0 !important; box-shadow: none !important;
}
.arctica-3d-design-thumb {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 4px; overflow: hidden;
  background: #f2f2f2; border: 1px solid #e3e3e3;
}
.arctica-3d-design-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.arctica-3d-design-text { display: block; min-width: 0; }
.arctica-3d-design-name {
  display: block; font: 500 13.5px/1.3 system-ui, sans-serif; color: #1a1a1a;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.arctica-3d-design-when {
  display: block; margin-top: 2px;
  font: 400 12px/1.3 system-ui, sans-serif; color: #646970;
}
.arctica-3d-design-row-actions { flex: 0 0 auto; display: flex; gap: 10px; }
/* Renaming takes the whole row: the field replaces the name it is changing,
   which is the only place in the editor a design is ever named. */
.arctica-3d-design-rename { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; }
.arctica-3d-design-rename .arctica-3d-saving-name { flex: 1 1 160px; width: auto; }

/* ==========================================================================
   The immersive page.

   Only on the shell's own document, which the plugin renders in place of the
   theme's product template. @see includes/ImmersiveProduct.php

   The whole page is one fixed-height column: header, then a row that takes
   whatever is left. Nothing outside the rail scrolls, which is what lets the
   rail scroll on its own — an ancestor that scrolls would carry the sticky
   regions with it.
   ========================================================================== */
body.arctica-3d-immersive {
  /* The page is a column: whatever is rendered above the shell takes the height
     it asks for, and the shell takes what is left. The theme's header is in that
     column but asks for nothing — it is drawn over the stage when it is summoned
     (see "The site header" below) — so the shell has the whole window. No number
     here describes what is above it, so nothing has to be corrected when
     something there reflows. */
  display: flex; flex-direction: column;
  height: 100dvh;
  /* The document does not scroll — the rail does. An ancestor that scrolled
     would carry the pinned regions with it. */
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
}
/* The admin bar is fixed and WordPress offsets the whole document to clear it,
   so it is not an item this column can lay out — the window really is that much
   shorter, and only the shell can say so. Both numbers are WordPress's own.
   @see wp-includes/admin-bar.php, _admin_bar_bump_cb() */
body.arctica-3d-immersive.admin-bar { height: calc(100dvh - 32px); }
@media screen and (max-width: 782px) {
  body.arctica-3d-immersive.admin-bar { height: calc(100dvh - 46px); }
}
/* The shell sizes itself against whatever is above it rather than the other way
   round. */
.arctica-3d-app {
  box-sizing: border-box;
  display: flex; align-items: stretch;
  width: 100%;
  /* A `0` basis rather than `auto`. The shell's content is taller than the
     window, and an `auto` basis would offer that content height as the starting
     size — putting the column over budget and making it shrink every item to
     fit, whatever is above it included. From zero only those items ask for
     anything, so they keep their height and the shell takes the remainder exactly.
     `min-height: 0` for the same reason one level down: the rail's content must
     not be able to set a floor under the shell. */
  flex: 1 1 0; min-height: 0;
  margin: 0; padding: 0;
}
/* The stage takes everything the rail does not. `min-width: 0` because a flex
   item's default minimum is its content, and a canvas reports its buffer width
   — without it the viewer can push the rail off the screen. */
.arctica-3d-app__stage {
  position: relative;
  flex: 1 1 auto; min-width: 0; height: 100%;
  background: #f4f4f4;
}
/* A quick second press on a control must not zoom the page. Pinching still
   does, so the page can still be enlarged. */
body.arctica-3d-immersive { touch-action: manipulation; }
/* Where the garment is dragged. A drag that strays over a control or the strip,
   or a finger held still before it moves, must not select text or open the
   touch callout. The rail keeps both, for the product information. */
.arctica-3d-app__stage { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* The viewer fills the stage rather than sizing itself against the window: on
   this page the box it is given is already the right one, and the window-
   relative height the ordinary product page needs would be measured against
   the wrong thing. Beats the shared rule above, which is written for a viewer
   inside a theme's column. */
.arctica-3d-app__stage .arctica-3d-customizer,
.arctica-3d-app__stage .arctica-3d-customizer .arctica-3d-viewer {
  height: 100%; min-height: 0; max-height: none;
}
/* ---- The rail -------------------------------------------------------- */
/* Positioned, for Edit Graphic's copy to be laid over it as it fades out. */
.arctica-3d-app__rail {
  position: relative;
  box-sizing: border-box;
  display: flex; flex-direction: column;
  flex: 0 0 400px; width: 400px; height: 100%;
  background: #fff;
}
/* The only part of the document that scrolls. `overscroll-behavior` stops a
   flick that reaches the end of the rail from being handed to the page
   behind it, which on a touchpad reads as the whole layout twitching. */
.arctica-3d-app__scroll {
  order: 1;
  flex: 1 1 auto; min-height: 0;
  padding: 20px;
  overflow-y: auto; overscroll-behavior: contain;
}
/* Pinned. The button cannot leave its form — the variation selects and the
   editor's hidden fields are inside it — so the region is pinned whole. Its
   own scroll is a floor, not an expectation: a product with many variation
   rows must not be able to push the button off the rail. */
.arctica-3d-app__action {
  order: 2;
  flex: 0 0 auto; max-height: 45%;
  padding: 16px 20px;
  overflow-y: auto; overscroll-behavior: contain;
  background: #fff; border-top: 1px solid #e3e3e3;
}
.arctica-3d-app__action .quantity { margin-bottom: 10px; }
/* WooCommerce gives the cart form `margin-bottom: 2em`, which on an ordinary
   product page holds it off the meta and the tabs printed below it. Here the
   form is the last thing in a pinned region with nothing under it, so the
   margin is 32px of rail spent on a gap against the region's own edge — and the
   rail is the scarce dimension on this page.

   Four classes deep because core's selector is `.woocommerce div.product
   form.cart`, which carries three classes and two types. A shorter override
   would tie rather than win, and a tie is settled by whichever stylesheet the
   page happens to enqueue last. */
body.arctica-3d-immersive .arctica-3d-app__rail .arctica-3d-app__action form.cart {
  margin-bottom: 0;
}
/* Space between the controls and the product information below them. */
.arctica-3d-app__info { margin-top: 28px; }
/* ---- The footer sheet's trigger --------------------------------------- */
/* Low emphasis, and in the stage rather than the rail: next to the buy button
   a link to the returns policy is a way out of the purchase. */
/* 48px square, which is the floor for a control a thumb has to hit — and this one
   sits over the stage on a phone, where everything around it is a drag gesture
   that rotates the garment. A smaller target here is not a smaller button, it is
   a button that turns the model when it is missed. Rounded rather than circular:
   the glyph is a square panel on a square grid, and a round face around it reads
   as a badge rather than as the control it is. */
.arctica-3d-app__more {
  position: absolute; left: 16px; bottom: 16px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 48px; height: 48px; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82); color: #333; cursor: pointer;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.arctica-3d-app__more:hover, .arctica-3d-app__more:focus { background: #fff; color: #111; }
/* The artwork is inset from the target rather than filling it: the 48px is the
   area worth pressing, and 28px of glyph inside it leaves the icon room to read
   as an icon. `display: block` because an inline SVG sits on the text baseline,
   which centres its box and then drops the artwork below the centre. */
.arctica-3d-app__more svg { display: block; width: 28px; height: 28px; }
/* ---- The masthead ---------------------------------------------------- */
/* Top left, the corner the site header slides in over. The button wears the
   other stage controls' face and 48px target; the logo beside it has no face, as
   it has none in the header. */
.arctica-3d-app__masthead {
  position: absolute; left: 16px; top: 16px; z-index: 2;
  display: flex; align-items: center; gap: 14px;
}
/* How far down the stage the viewer keeps the zoomed-out garment, so the logo
   is not drawn over the collar on a short stage: the masthead's 16px inset, its
   48px, and 16px of air. The cart in the other corner is the same height. Only
   used where the stage is too short for the ordinary framing to clear it.
   @see src/viewer-core/Viewer.ts shape */
.arctica-3d-app__stage { --arctica-3d-clear-top: 80px; }
/* The theme paints every `button` black with a pill radius and repaints it on
   hover, so the face is stated in full and so are its hover and focus states. */
.arctica-3d-app__menu {
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 48px; height: 48px; margin: 0; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82); color: #333; cursor: pointer;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.arctica-3d-app__menu:hover, .arctica-3d-app__menu:focus { background: #fff; color: #111; }
.arctica-3d-app__menu svg { display: block; width: 24px; height: 24px; }
/* The site's name, where there is no logo to show. */
.arctica-3d-app__home {
  display: block;
  color: #111; font-size: 16px; font-weight: 700; text-decoration: none;
}
/* The height the theme's header draws its logo at. */
.arctica-3d-app__home img { display: block; width: auto; height: 28px; }
/* ---- The site header ------------------------------------------------- */
/* Out of the column and off the top of the window until the menu button, the
   side cart or the theme's phone menu asks for it. @see src/customizer/Shell.ts

   Zero height is how the theme itself takes its header out of the page for a
   see-through header, and `!important` is there for the same reason: the theme's
   script writes the header's height onto this element inline. The header inside
   is fixed by that script and does not need the room.

   Hidden by the stylesheet rather than by script, so it is off the window in the
   first frame instead of shown and then taken away. `visibility` as well as the
   slide, because a header moved out of sight is still in the tab order. Held
   until the slide has finished, so there is still something to watch leave. */
body.arctica-3d-immersive #navigation { height: 0 !important; }
body.arctica-3d-immersive #navigation header {
  transform: translateY(-101%);
  visibility: hidden;
  transition: transform 0.2s ease-in-out, visibility 0s linear 0.2s;
}
body.arctica-3d-immersive.arctica-3d-header-open #navigation header {
  transform: none;
  visibility: visible;
  transition: transform 0.2s ease-in-out, visibility 0s;
}
/* On for as long as the header is. The theme's script takes the curtain away
   whenever its menu closes, and on this page that is not the header going. */
body.arctica-3d-immersive.arctica-3d-header-open #nav-curtain { opacity: 1; pointer-events: auto; }
/* The theme locks the page's scroll while its side cart or phone menu is open,
   by writing `position: fixed`, a `top`, a `width` and `overflow-y: scroll` onto
   the body. This document never scrolls, so there is nothing to lock, and two of
   those do harm here: the forced scrollbar narrows the page behind the curtain,
   and `top` is measured from the top of the window, which lifts the page under
   the admin bar and leaves a strip at the bottom. `!important` because the
   theme writes them inline. `top: auto` keeps a fixed body where it already was;
   `position` is left to the theme, whose script reads it back to know there is a
   lock to release when the panel closes. */
body.arctica-3d-immersive { top: auto !important; overflow-y: hidden !important; }
/* The header takes focus when it opens, so that the next Tab reaches its first
   link. It is not in the tab order itself, so a ring would report nothing. */
body.arctica-3d-immersive #navigation header:focus { outline: none; }
@media (prefers-reduced-motion: reduce) {
  body.arctica-3d-immersive #navigation header,
  body.arctica-3d-immersive.arctica-3d-header-open #navigation header { transition: none; }
}
/* ---- The cart button ------------------------------------------------- */
/* Top right, the end of the stage where the site header keeps its own cart,
   wearing the other stage controls' face and 48px target. */
.arctica-3d-app__cart {
  position: absolute; right: 16px; top: 16px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 48px; height: 48px; margin: 0; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82); color: #333; text-decoration: none;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.arctica-3d-app__cart:hover, .arctica-3d-app__cart:focus { background: #fff; color: #111; }
.arctica-3d-app__cart svg { display: block; width: 24px; height: 24px; }
/* The header's badge, restated rather than borrowed: the theme's rule is written
   for its own link. Placed where the theme places it on the glyph — 70% of the
   way across, lifted by 30% of its own height — with the glyph centered here. */
.arctica-3d-app__cartcount {
  position: absolute; left: calc(50% + 5px); top: calc(50% - 17px);
  box-sizing: border-box; min-width: 16px; height: 16px; padding: 0 5px;
  border-radius: 8px; background: #eb342e; color: #fff;
  font-size: 12px; line-height: 16px; text-align: center;
}
/* ---- The screenshot button ------------------------------------------- */
/* Under the cart, for an administrator only, in the same face. 72px is the
   cart's 16px inset, its 48px, and 8px between the two. The face is stated in
   full, with its hover and focus, for the theme's reason given at the menu. */
.arctica-3d-app__screenshot {
  position: absolute; right: 16px; top: 72px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 48px; height: 48px; margin: 0; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82); color: #333; cursor: pointer;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.arctica-3d-app__screenshot:hover, .arctica-3d-app__screenshot:focus { background: #fff; color: #111; }
/* While the picture is made. */
.arctica-3d-app__screenshot:disabled { color: #999; cursor: progress; }
.arctica-3d-app__screenshot svg { display: block; width: 24px; height: 24px; }
/* ---- The Save button ------------------------------------------------- */
/* Bottom right, in the corner opposite the footer trigger, wearing the stage
   controls' face and 48px target: saving acts on the whole design, as they do.
   Icon only, like them; the words stay in the label and the tooltip. */
.arctica-3d-app__stage > .arctica-3d-savebtn {
  position: absolute; right: 16px; bottom: 16px; z-index: 2;
  justify-content: center;
  box-sizing: border-box; width: 48px; height: 48px; margin: 0; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82); color: #333;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}.arctica-3d-app__stage > .arctica-3d-savebtn:hover,
.arctica-3d-app__stage > .arctica-3d-savebtn:focus { background: #fff; color: #111; }
/* 22px rather than the neighbors' 28px: this glyph fills its whole box, where
   theirs leave a margin inside it, so 22px draws at about their size. */
.arctica-3d-app__stage > .arctica-3d-savebtn svg { width: 22px; height: 22px; }
.arctica-3d-app__stage > .arctica-3d-savebtn .arctica-3d-savebtn__label {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* ---- Undo and Redo --------------------------------------------------- */
/* Anywhere but the immersive page: a line of their own above Save, under the
   rows, in Save's outline. */
.arctica-3d-undo { display: flex; gap: 6px; margin-top: 14px; }
.arctica-3d-undo__btn {
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 34px; height: 32px; margin: 0; padding: 0; cursor: pointer;
  border: 1px solid #1a1a1a; border-radius: 4px; background: none; color: #1a1a1a;
}
.arctica-3d-undo__btn svg { display: block; width: 20px; height: 20px; }
.arctica-3d-undo__btn:disabled { border-color: #c4c4c4; color: #b4b4b4; cursor: default; }
/* On the stage, above Save, in the zoom's face: one control with two positions,
   Undo over Redo. The bottom right holds the controls pressed most while
   editing, beside the rail they edit with and under a right thumb on a phone.
   72px is Save's 16px inset, its 48px, and 8px between the two. */
.arctica-3d-app__stage > .arctica-3d-undo {
  position: absolute; right: 16px; bottom: 72px; z-index: 2;
  flex-direction: column; gap: 0;
  box-sizing: border-box; width: 48px; margin: 0;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn {
  width: 100%; height: 48px;
  border: none; border-radius: 0; box-shadow: none;
  background: none; color: #333;
  -webkit-appearance: none; appearance: none;
}
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn + .arctica-3d-undo__btn {
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn:hover,
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn:focus { background: #fff; color: #111; }
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn:disabled { background: none; color: #b4b4b4; cursor: default; }
.arctica-3d-app__stage > .arctica-3d-undo .arctica-3d-undo__btn svg { width: 28px; height: 28px; }
/* ---- The zoom controls ----------------------------------------------- */
/* Wearing the footer trigger's face and 48px target: both are controls the
   shopper reaches for over the garment rather than in the rail, and two
   different treatments would read as two different kinds of thing.

   One border and one radius, on the group rather than on each segment. Three
   separately bordered buttons stacked read as three decisions; this is one
   control with three positions, and the only line drawn between them is the
   divider. `overflow: hidden` so the segments are clipped by the group's
   corners instead of squaring them off. */
/* 48px wide including the border, which is the footer trigger's outer measure:
   the border belongs to the group here and to the button there, so matching the
   two means matching what is drawn, not what is inside it. */
.arctica-3d-zoom {
  position: absolute; right: 16px; bottom: 16px; z-index: 2;
  display: flex; flex-direction: column;
  box-sizing: border-box; width: 48px;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 12px;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
/* On the stage, centered on the left edge, between the menu button and the
   footer trigger: the wheel and a pinch zoom too, so these are pressed less
   than Undo and Save, which keep the bottom right. Centered on the garment's
   own area, so the strip below it on a phone does not pull it off center. */
.arctica-3d-app__stage > .arctica-3d-zoom {
  left: 16px; right: auto; top: 50%; bottom: auto;
  transform: translateY(-50%);
}
.arctica-3d-zoom__btn {
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 100%; height: 48px; padding: 0;
  border: none; border-radius: 0; box-shadow: none;
  background: none; color: #333; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
/* Between segments only, so no line runs out to the rounded corners. */
.arctica-3d-zoom__btn + .arctica-3d-zoom__btn { border-top: 1px solid rgba(0, 0, 0, 0.1); }
.arctica-3d-zoom__btn:hover, .arctica-3d-zoom__btn:focus { background: #fff; color: #111; }
/* At a bound, and saying so. A control that stays lit and does nothing when it
   is pressed reads as broken; one that is visibly spent reads as a limit. After
   the hover rule, which otherwise lights a segment that cannot act. */
.arctica-3d-zoom__btn:disabled { background: none; color: #b4b4b4; cursor: default; }
/* Same glyph size as the footer trigger. Both are icon buttons on the same
   stage, and an icon that is a few pixels smaller than its neighbour does not
   read as a smaller icon — it reads as a mistake. */
.arctica-3d-zoom__btn svg { display: block; width: 28px; height: 28px; }
/* ---- The sheet ------------------------------------------------------- */
/* A native dialog, so focus, Escape and stacking are the browser's. In the top
   layer it is above every fixed element on the page without a z-index being
   reasoned about — which matters here, where the theme's header, its curtain
   and its side cart are each fixed and each have one of their own. */
/* `clip` rather than `hidden`, and the difference is the whole reason the panel
   used to arrive most of the way already there.

   Both clip to the same box, but `hidden` makes this a scroll container and
   `clip` does not — and the panel is a child that overflows it by its own height
   for the length of the slide. Measured against the animation's timeline, a
   panel 772px tall inside the `hidden` version rendered its opening frame 302px
   down instead of 772: the travel was clamped to the scrollport, so two thirds
   of the slide never existed and what was left of it finished at the halfway
   point of its duration. Under `clip` the same animation renders 772 at 0ms and
   386 — exactly half — at 160ms.

   Nothing here ever wanted a scroll container. The panel scrolls, and it says so
   itself; this element is a full-window frame whose only job is to clip what
   hangs below it. `hidden` first, so a browser without `clip` keeps the
   behaviour it already had rather than losing the clipping altogether. */
.arctica-3d-sheet {
  width: 100%; max-width: none; max-height: 100%; height: 100%;
  margin: 0; padding: 0; border: none; background: none;
  overflow: hidden;
  overflow: clip;
}
.arctica-3d-sheet::backdrop { background: rgba(0, 0, 0, 0); -webkit-backdrop-filter: blur(0); backdrop-filter: blur(0); }
/* The theme's own curtain values, so a sheet the plugin opens and a menu the
   theme opens dim the page by the same amount over the same interval. */
.arctica-3d-sheet[open]::backdrop {
  background: rgba(0, 0, 0, 0.2);
  -webkit-backdrop-filter: blur(0.8rem); backdrop-filter: blur(0.8rem);
  transition: background .32s ease-in, backdrop-filter .32s ease-in;
}
/* Slides from the bottom, which is where the footer was.

   No surface of its own: what this shows is the site footer, which arrives with
   its own background, its own gutters and its own top edge. A panel that painted
   anything would be a second surface showing around the first — a white band
   above a dark footer, and white margins down its sides. So this positions and
   animates, and paints nothing. */
.arctica-3d-sheet__panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  box-sizing: border-box;
  max-height: 100%;
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateY(100%); transition: transform .32s cubic-bezier(.4, 0, .6, 1);
}
/* The panel takes focus when the sheet opens so that the close button does not.
   It is not in the tab order and cannot be reached by pressing anything, so it
   has no state a ring would be reporting — and a ring around the whole footer is
   read as the footer being selected. @see includes/ImmersiveProduct.php */
.arctica-3d-sheet__panel:focus { outline: none; }
/* Opening is an animation and closing is a transition. The two directions are
   not the same problem.

   A transition needs a start state the browser has already rendered, and the
   panel's ancestor is `display: none` until showModal() — so `translateY(0)` is
   simply the first value the panel ever computes, and a first value is not a
   change to transition. A keyframe animation carries its own start value, so it
   has nothing to travel from and runs on the frame the element first renders.

   Closing has the opposite shape: the element is already rendered, so the
   transition below is all it needs — and an animation there would be worse,
   because the dialog has to stay open until the slide finishes and a class is
   what says when that is. @see src/customizer/Shell.ts

   Same duration and same curve in both directions, so the open is the close run
   backwards. */
.arctica-3d-sheet[open] .arctica-3d-sheet__panel {
  transform: translateY(0);
  animation: arctica-3d-sheet-in .32s cubic-bezier(.4, 0, .6, 1);
}
@keyframes arctica-3d-sheet-in {
  from { transform: translateY(100%); }
}
/* Still open, and on its way out. A dialog closed outright leaves the top layer
   in the same frame, taking the panel with it before it can animate — so the
   sheet stays open under this class until the slide has finished.
   @see src/customizer/Shell.ts */
.arctica-3d-sheet[open].is-closing .arctica-3d-sheet__panel { transform: translateY(100%); }
.arctica-3d-sheet[open].is-closing::backdrop {
  background: rgba(0, 0, 0, 0);
  -webkit-backdrop-filter: blur(0); backdrop-filter: blur(0);
}
/* The nudge, over the footer's own top padding. Sticky rather than placed, so it
   stays reachable once the footer is scrolled.

   Pressing the dimmed page closes the sheet too, and is the larger target — but
   it is invisible and it is a pointer only. This is the affordance saying the
   sheet can be put away, and the only way to put it away from the keyboard other
   than Escape. So it stays, and it is drawn as an arrow rather than a control:
   no surface of its own in any state. The theme paints every `button` black with
   a pill radius and repaints it on hover, which is what has to be turned off
   here — selectors carry the extra class so they outrank it. */
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge,
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:hover,
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:focus,
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:active {
  background: none; border: none; border-radius: 0; box-shadow: none;
  transition: none;
}
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 58px; margin: 0; padding: 0;
  cursor: pointer;
}
/* Drawn from two borders, like the panel's other chevrons, so the sheet needs no
   icon font and no inline SVG. */
.arctica-3d-sheet__chevron {
  display: block; width: 26px; height: 26px; margin-top: -11px;
  border-right: 2px solid #fff; border-bottom: 2px solid #fff;
  opacity: .55; transform: rotate(45deg); transition: opacity .2s ease;
}
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:hover .arctica-3d-sheet__chevron,
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:focus-visible .arctica-3d-sheet__chevron { opacity: 1; }
/* Focus has to be visible on its own terms: the rules above strip the theme's
   button surface in every state, which takes its focus styling with it, and the
   chevron brightening is a change of degree rather than something a keyboard
   user can find. Inset, so the ring sits over the footer rather than on the seam
   between the footer and the dimmed page. */
.arctica-3d-sheet__panel .arctica-3d-sheet__nudge:focus-visible {
  outline: 2px solid #fff; outline-offset: -8px; border-radius: 6px;
}
/* One transform on the way up, not two.

   The theme gives `#footer-main` `transform: translateY(0)` and a transition on
   it — a resting value nothing in the theme ever changes, because what it is
   there for is the reveal on an ordinary page. Inside the sheet it is a second
   transform on the same axis as the panel's, nested inside it: two composited
   layers, an outer one animating and an inner one the compositor is free to
   raster and update on its own schedule. A frame where the inner layer has not
   caught up is a panel whose frame has moved and whose contents have not, which
   is the shift at the end of the slide.

   Removing the transform removes the layer, and the panel travels as one box.
   The transition goes with it: it exists to animate the property being dropped
   here, so on its own it is a declaration waiting for something that can no
   longer happen. */
.arctica-3d-sheet #footer-main { transform: none; transition: none; }
/* The footer's menus reveal on scroll: the theme starts them at `opacity: 0` and
   adds `active` to `#footer-main` once the window has scrolled far enough down
   the document. This page does not scroll, so that never fires and the sheet
   opens on a footer with nothing in it. The sheet is its own reveal, so the
   reveal here is simply off. */
.arctica-3d-sheet #footer-main .widget_nav_menu .widget-title,
.arctica-3d-sheet #footer-main .widget_nav_menu li {
  opacity: 1; visibility: visible; transition: none;
}
@media (prefers-reduced-motion: reduce) {
  .arctica-3d-sheet__panel, .arctica-3d-sheet[open]::backdrop { transition: none; }
}
/* All four belong to the panel the rail becomes further down. A rail that is
   permanently on show has nothing to open, name or dismiss, covers nothing, and
   nothing it holds has to be carried out onto the stage to stay reachable. */
.arctica-3d-app__customize, .arctica-3d-app__panelbar, .arctica-3d-app__curtain,
.arctica-3d-strip { display: none; }

/* ---- Phone and small tablet ------------------------------------------
   Below this width there is no room for a rail beside the stage, and the two
   things that want the window — the garment and the controls — are co-equal
   halves of one task rather than a subject and a note about it.

   So they are swapped, not overlapped. The rail keeps being a rail and becomes
   a panel that enters from the side, covering the stage on a phone and sitting
   beside it on a tablet; the stage keeps everything the panel is not using. One
   surface at a time, with a labelled control in each saying how to reach the
   other.

   Which edge a surface comes from is the whole of what the shopper has to go on,
   so the two edges say different things here and only one thing each. The side
   is another surface at the same level. The bottom is reserved for the footer
   sheet, which is a note about the page — and the reason a bottom sheet was
   wrong for the controls is exactly that it claimed the same edge for the
   opposite meaning.

   The shell stays fixed-height rather than reverting to page flow: the panel
   needs something full-height to sit against, and `dvh` already accounts for
   the browser's own retracting chrome.
   -------------------------------------------------------------------- */
@media (max-width: 900px) {
  /* Still a flex row, so the stage takes the width on its own once the rail has
     left the flow. `position: relative` because the panel is positioned against
     the shell rather than against the stage: it is the stage's peer here, not
     something laid over it.

     `overflow` because a closed panel is parked one full width to the right of
     this box, and a parked panel must not make the page wider than the screen.
     The body's own `overflow: hidden` does not cover it: an `overflow` set on
     the body propagates to the viewport, and the body element is then left
     computing to `visible` and clipping nothing of its own. So the page stops
     scrolling while the overflow is still there — invisible until the browser is
     zoomed, at which point panning reaches it and finds a screen's worth of
     nothing beside the garment. Clipped here instead, on an ordinary element
     that clips for real. */
  .arctica-3d-app { position: relative; overflow: hidden; }

  /* ---- The stage ---- */
  /* Two rows: the garment, then the control that opens the panel. A row rather
     than an overlay, because a bar drawn on top of a 3D view hides part of the
     only thing the view is for — and this one is permanent, so what it covered
     would never come back. `minmax(0, 1fr)` for the same reason the shell uses a
     zero basis: a canvas reports its buffer as its minimum and would otherwise
     put a floor under the row. The two corner controls are absolutely positioned
     and take no part in this. */
  .arctica-3d-app__stage { display: grid; grid-template-rows: minmax(0, 1fr) auto auto; }
  /* The strip is appended by the editor and the bar is printed by the template,
     so the two arrive in the stage in the wrong order for the one they are read
     in. Ordered rather than moved: where a control is rendered is a question
     about which code owns it, and where it sits is a question about the page. */
  .arctica-3d-app__customize {
    order: 2;
    display: flex; align-items: center; justify-content: center; gap: 10px;
    box-sizing: border-box; width: 100%; min-height: 56px; padding: 14px 20px;
    border: none; border-radius: 0;
    background: #111; color: #fff;
    font: inherit; font-size: 15px; font-weight: 600; letter-spacing: 0.02em;
    cursor: pointer;
    -webkit-appearance: none; appearance: none;
  }
  .arctica-3d-app__customize svg { display: block; width: 24px; height: 24px; }

  /* ---- The color strip ---- */
  /* The one control that stays out on the stage when the panel is dismissed.
     Choosing which part to work on is reading and belongs in the panel; changing
     the color of the part already chosen is watching the garment, and it cannot
     be done from behind a surface that covers the garment. @see
     src/customizer/Customizer.ts for which color it carries and why.

     `:not([hidden])` so the editor can still take it away: an attribute the UA
     sheet hides with `display: none` loses to a class rule of the same weight
     written after it. */
  /* The open row's controls, laid out as a stack of single lines. Everything the
     panel would have shown under that row's name is here — the bases to choose
     from and the colors — because all of it is judged by looking at the
     garment. */
  .arctica-3d-strip:not([hidden]) {
    order: 1;
    display: flex; flex-direction: column; gap: 8px;
    box-sizing: border-box; min-width: 0; padding: 10px 14px;
    border-top: 1px solid #e3e3e3;
    background: #fff;
  }
  /* The row's name. In the panel the row's own head says what the controls
     belong to; on the stage that head is still in the panel, so without
     this the shopper is holding a row of swatches with nothing saying what they
     paint. */
  .arctica-3d-strip-title {
    flex: 0 0 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    color: #767676;
  }
  /* The title, and on an open logo, Edit Graphic's X at the end of the line. */
  .arctica-3d-strip-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
  .arctica-3d-strip-head .arctica-3d-strip-title { flex: 1 1 auto; min-width: 0; }
  .arctica-3d-strip .arctica-3d-iconbtn.arctica-3d-graphic-close { margin: -10px -12px -10px 0; }
  /* The row's own body, moved here from the panel rather than rendered a second
     time. @see src/customizer/Customizer.ts homeBody */
  .arctica-3d-strip .arctica-3d-panel-body {
    display: flex; flex-direction: column; gap: 8px;
    min-width: 0; padding: 0;
  }
  .arctica-3d-strip .arctica-3d-region { gap: 10px; margin: 0; }
  /* A fixed column rather than a share of the line. The swatches want every
     pixel they can get and will take them from anything able to give: against a
     shrinkable label that means one letter and an ellipsis, which names nothing.
     Sized for the one word these labels are, with truncation left in as a
     backstop rather than as the normal case. */
  .arctica-3d-strip .arctica-3d-region-label {
    flex: 0 0 66px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12px; font-weight: 600; color: #333;
  }
  /* Every group in the strip is one line that scrolls, never a grid that wraps.
     A wrapping row makes the strip as tall as the template happens to be wide —
     how much of the garment is left would be decided by how many colors or
     graphics somebody authored, which is not a thing the layout should be
     answering.

     The padding is the selected item's ring, drawn outside its own box and
     otherwise cut off by the scroll box on the row's first, last, top and bottom
     edges. The negative margin takes the same distance back off the outside, so
     the ring has room without the row sitting indented from the label beside it.

     On the right it goes further and takes the strip's whole gutter, so the
     scroll box ends where the bar does. A scroll box inset from the edge cuts its
     content off early and leaves a clear margin after it, which reads as the row
     having ended — the one thing a row that continues must not say. The gutter
     comes back as padding inside, so a row short enough to fit still sits off the
     edge.

     No scrollbar. It is drawn inside the scroll box, so it lies across the bottom
     of the very things it is scrolling — and there is one scroller per line here,
     which would put a bar between every row. What says a row continues is the
     item cut off at the edge, which is how a touch carousel says it everywhere
     else. */
  .arctica-3d-strip .arctica-3d-swatches,
  .arctica-3d-strip .arctica-3d-bases,
  .arctica-3d-strip .arctica-3d-fonts {
    display: flex; flex: 1 1 auto; flex-wrap: nowrap; min-width: 0;
    gap: 8px; padding: 5px 14px 5px 5px; margin: -5px -14px -5px -5px;
    overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -ms-overflow-style: none;
  }
  .arctica-3d-strip .arctica-3d-swatches::-webkit-scrollbar,
  .arctica-3d-strip .arctica-3d-bases::-webkit-scrollbar,
  .arctica-3d-strip .arctica-3d-fonts::-webkit-scrollbar { width: 0; height: 0; }
  /* The fonts on one line with the others, each tile as wide as its sample. */
  .arctica-3d-strip .arctica-3d-logo-field.arctica-3d-fontfield { align-items: center; }
  .arctica-3d-strip .arctica-3d-fontfield .arctica-3d-logo-key { padding-top: 0; }
  .arctica-3d-strip .arctica-3d-fonttile { flex: 0 0 auto; height: 34px; padding: 0 12px; }
  /* Larger than the panel's. Those sit in a list that is already being read;
     these sit against a canvas where every neighbouring pixel is a drag that
     turns the garment, so a miss here is not a miss, it is a rotation. */
  .arctica-3d-strip .arctica-3d-swatch { flex: 0 0 auto; width: 34px; height: 34px; }
  /* An open picker in place of the row's controls, one line per slider, as the
     strip's other lines are. The strip's X goes back to the swatches. */
  .arctica-3d-strip .arctica-3d-panel-body.is-picking > :not(.arctica-3d-picker) { display: none; }
  .arctica-3d-strip .arctica-3d-picker {
    display: flex; flex-direction: column; gap: 8px;
    margin: 0; padding: 0; border: none;
  }
  .arctica-3d-strip .arctica-3d-picker .arctica-3d-logo-key { flex-basis: 76px; }
  /* Sized by the line rather than by the column they no longer sit in, since the
     name sits under the picture, and a base called "Long Sleeve Pro" in a
     narrower column is four lines of two syllables. */
  .arctica-3d-strip .arctica-3d-bases .arctica-3d-base-tile { flex: 0 0 58px; width: 58px; font-size: 10.5px; }
  /* The open logo's lines, labelled like the colors above them. Its picture
     sits beside what the file is rather than over it: every line here is
     garment the shopper cannot see. */
  .arctica-3d-strip .arctica-3d-logo-file,
  .arctica-3d-strip .arctica-3d-logo-field,
  .arctica-3d-strip .arctica-3d-logo-dpi,
  .arctica-3d-strip .arctica-3d-debug,
  .arctica-3d-strip .arctica-3d-note { margin: 0; }
  .arctica-3d-strip .arctica-3d-logo-file { display: flex; align-items: center; gap: 10px; }
  .arctica-3d-strip .arctica-3d-logo-preview { flex: 0 0 auto; width: 56px; height: 56px; padding: 4px; }
  .arctica-3d-strip .arctica-3d-logo-about { flex: 1 1 auto; min-width: 0; align-items: center; margin: 0; }
  .arctica-3d-strip .arctica-3d-logo-key { flex-basis: 66px; font-size: 12px; font-weight: 600; }

  /* Gone while the panel is open. The color it carries is on screen in the
     panel, and two live copies of one control leave the shopper deciding which
     of them is the real one. */
  .arctica-3d-app:has(.arctica-3d-app__rail.is-open) .arctica-3d-strip { display: none; }

  /* ---- The rail, as a panel ---- */
  /* `min()` rather than a plain width: on a phone the panel is the screen, and on
     a tablet at the top of this range it is the rail's own measure with the
     garment still beside it. One declaration covers both, and nothing has to
     choose a second breakpoint to say where a panel stops being a screen.

     Above the corner controls, which sit at `z-index: 2` in the stage. */
  .arctica-3d-app__rail {
    position: absolute; top: 0; right: 0; bottom: 0; z-index: 4;
    flex: 0 0 auto; width: min(400px, 100%); height: auto;
    border-left: 1px solid #e3e3e3;
    box-shadow: -6px 0 24px rgba(0, 0, 0, 0.12);
    transform: translateX(100%);
    /* Not just moved aside: an off-screen panel is still in the tab order and
       still read out, and a shopper would tab from the buy control into a
       surface that is not on screen. `visibility` is held until the slide has
       finished so the panel is still there to animate. */
    visibility: hidden;
    transition: transform 0.28s ease, visibility 0s linear 0.28s;
  }
  .arctica-3d-app__rail.is-open {
    transform: none;
    visibility: visible;
    transition: transform 0.28s ease, visibility 0s;
  }
  /* Mid-rotation. The layout either side of the breakpoint puts the panel in a
     different place for different reasons, and a transition across that is not
     the panel moving — it is one layout's resting position animating to
     another's. After the `is-open` rule, so it also stops the arriving layout
     from animating a panel that is already open. @see src/customizer/Shell.ts */
  .arctica-3d-app__rail.is-switching,
  .arctica-3d-app__rail.is-switching.is-open { transition: none; }
  /* Over the garment while the panel is open, as the theme's curtain is under its
     side cart, with the theme's own values; a press on it closes the panel. Under
     the panel and over the corner controls. `visibility` is held until the fade
     has finished, like the panel's, and takes the blur off the canvas once it
     has. @see src/customizer/Shell.ts wireRail */
  .arctica-3d-app__curtain {
    display: block;
    position: absolute; inset: 0; z-index: 3;
    background: rgba(0, 0, 0, 0.2);
    -webkit-backdrop-filter: blur(0.8rem); backdrop-filter: blur(0.8rem);
    opacity: 0; visibility: hidden;
    transition: opacity 0.32s ease-in, visibility 0s linear 0.32s;
  }
  .arctica-3d-app__rail.is-open ~ .arctica-3d-app__curtain {
    opacity: 1; visibility: visible;
    transition: opacity 0.32s ease-in, visibility 0s;
  }
  .arctica-3d-app__rail.is-switching ~ .arctica-3d-app__curtain { transition: none; }

  /* Title and the way back. First in the panel, and ordered explicitly like the
     two regions below it so none of the three depends on the source. Set like
     the theme's side cart title, with no rule under it: the line over the first
     row, directly below, is the one rule between the title and the list. */
  .arctica-3d-app__panelbar {
    order: 0; display: flex; align-items: center; justify-content: space-between;
    flex: 0 0 auto; padding: 6px 6px 6px 20px;
  }
  .arctica-3d-app__panelname { font-size: 24px; font-weight: 500; color: #000; }
  /* The product's own title and subtitle, which would sit under the bar, are
     hidden by the theme at this width, so the list starts at the top of the
     scrolling region rather than a gutter below it. */
  .arctica-3d-app__scroll { padding-top: 0; }
  /* The same 48px target and 24px glyph as the controls over the stage. */
  .arctica-3d-app__close {
    display: flex; align-items: center; justify-content: center;
    box-sizing: border-box; width: 48px; height: 48px; padding: 0;
    border: none; border-radius: 0; box-shadow: none;
    background: none; color: #333; cursor: pointer;
    -webkit-appearance: none; appearance: none;
  }
  .arctica-3d-app__close:hover, .arctica-3d-app__close:focus { color: #111; }
  .arctica-3d-app__close svg { display: block; width: 24px; height: 24px; }

  /* The corner controls stay in the corners they hold on a desktop stage, by
     being pinned to the garment's row rather than to the whole stage. An
     absolutely positioned child of a grid container is laid out against the grid
     area it is given, so naming the garment's row is the whole of it — no offset
     has to be worked out for the strip and the bar below, and none has to be
     revised when the strip changes height with the open row.

     Both edges of that area are named. An `auto` end line on an out-of-flow grid
     child does not mean "the end of the row it started in" — it means the grid
     container's own padding edge, so half a placement here is no placement at
     all and the control ends up pinned to the bottom of everything. */
  .arctica-3d-app__more, .arctica-3d-zoom, .arctica-3d-app__masthead, .arctica-3d-app__cart,
  .arctica-3d-app__screenshot, .arctica-3d-app__stage > .arctica-3d-savebtn,
  .arctica-3d-app__stage > .arctica-3d-undo { grid-row: 1 / 2; grid-column: 1 / 2; }
}
/* The panel is where it is either way; what is dropped is the travel. */
@media (max-width: 900px) and (prefers-reduced-motion: reduce) {
  .arctica-3d-app__rail, .arctica-3d-app__rail.is-open,
  .arctica-3d-app__curtain, .arctica-3d-app__rail.is-open ~ .arctica-3d-app__curtain { transition: none; }
}
