/* Shared physical scale visual for the landing page and the Studio order
   step. Loaded after figuren.css / studio.css on both pages and owns the
   whole scene, so the scale lives in exactly one file.

   One scale for everything: --cm is the pixels-per-centimetre of the scene
   and every object is drawn at height = its real size in cm x --cm. The
   silhouette viewBoxes are tight around their artwork, so the drawn height
   equals the element height and no object is quietly short.

     object     real size   viewBox     width / height
     Buch       21.5 cm     48 x 94     0.510638
     Figur       8/12/18 cm 68 x 93.5   0.727273
     Hand       19   cm     54 x 80.5   0.670807
     Espresso    7   cm     59 x 48     1.229167

   Scene width at the largest figure, in centimetres:
     Buch     21.5 x 0.510638 = 10.979
     Figur    18   x 0.727273 = 13.091
     Hand     19   x 0.670807 = 12.745
     Espresso  7   x 1.229167 =  8.604
                                -------
                                 45.419   -> --scene-cm below

   --cm is therefore capped by the width the stage actually has, measured
   with container query units against .size-demo. That is what keeps the
   scene honest at every width: previously each silhouette carried
   max-width: 100%, so a narrow column silently shrank the hand and the
   18 cm figure below their own scale while the neighbours kept theirs.

   Every ground shadow is derived from its own object: width = that
   object's rendered width x its contact fraction, centred on the object's
   contact centre. The figure's shadow therefore grows with the selected
   size instead of staying put. */

.size-demo {
  container-type: inline-size;
  width: 100%;
  --figur-cm: 12;
}

/* The chooser is part of the component and its state is the checked
   radio, so nothing has to mirror the selection into an attribute and no
   page script has to run for the scene to follow the choice. This file is
   the only place the three sizes are wired to anything. */
.size-demo:has(input[name="size"][value="80"]:checked) { --figur-cm: 8; }
.size-demo:has(input[name="size"][value="120"]:checked) { --figur-cm: 12; }
.size-demo:has(input[name="size"][value="180"]:checked) { --figur-cm: 18; }

/* --- chooser ------------------------------------------------------------

   Lived in figuren.css until 31.08.2026, which is why the Studio never had
   it and grew a second control of its own. It belongs to the component. */

.size-buttons {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.size-btn {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  padding: 0.5rem 1.05rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
}

/* The radio carries the state and the keyboard behaviour; the pill is its
   visible form, so the input itself is taken out of sight rather than out
   of the accessibility tree. */
.size-btn input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  pointer-events: none;
}

.size-btn:hover { background: var(--hover-tint); border-color: var(--ink); }

.size-btn:has(input:checked) {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--surface);
}

.size-btn:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Filled in by the Studio once /api/pricing answers. Empty everywhere
   else, so both pages render the same pill until there is a price. */
.size-btn-price { font-size: 0.76rem; font-weight: 500; opacity: 0.75; }
.size-btn-price:empty { display: none; }

/* The readout carries all three numbers and the stylesheet shows the
   chosen one, so the selection needs no script here either. */
.size-readout > [data-cm] { display: none; }
.size-demo:has(input[name="size"][value="80"]:checked)
  .size-readout > [data-cm="80"],
.size-demo:has(input[name="size"][value="120"]:checked)
  .size-readout > [data-cm="120"],
.size-demo:has(input[name="size"][value="180"]:checked)
  .size-readout > [data-cm="180"] { display: block; }

.size-stage {
  /* Surface treatment used to be written twice, once per page stylesheet,
     and the copies had drifted: the Studio drew the labels at 0.58rem in
     --dim with no leader tick and no accent readout, on a flat ground
     rather than the gradient. Both pages read these declarations now. */
  margin-top: 1.6rem;
  background: linear-gradient(180deg, var(--surface-2) 0%, #efe9e0 100%);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);

  --scene-cm: 45.5;
  --book-cm: 21.5;
  --hand-cm: 19;
  --tasse-cm: 7;
  --figur-max-cm: 18;
  --stage-pad: clamp(0.5rem, 2cqw, 1.15rem);
  --stage-top: 0.75rem;
  --floor: 14px;
  --label-row: 2.05rem;
  /* the 56px allowance covers both stage paddings plus the three minimum
     column gaps, so the objects never have to be clamped to fit */
  --cm: min(10px, calc((min(100cqw, 640px) - 56px) / var(--scene-cm)));

  position: relative;
  display: grid;
  grid-template-columns:
    calc(var(--book-cm) * var(--cm) * 0.510638)
    calc(var(--figur-max-cm) * var(--cm) * 0.727273)
    calc(var(--hand-cm) * var(--cm) * 0.670807)
    calc(var(--tasse-cm) * var(--cm) * 1.229167);
  justify-content: space-between;
  align-items: stretch;
  gap: 0;
  width: 100%;
  max-width: 640px;
  height: calc(var(--stage-top) + var(--label-row)
    + var(--book-cm) * var(--cm) + var(--floor));
  padding: var(--stage-top) var(--stage-pad) var(--floor);
  overflow: hidden;
}

.size-floor {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--floor);
  height: 1px;
  background: var(--line);
}

.size-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  margin-bottom: 0.55rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  color: var(--faint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* leader tick between label and object */
.size-label::after {
  content: "";
  width: 1px;
  height: 10px;
  background: var(--line);
}

.size-readout {
  color: var(--accent-deeper);
  font-weight: 700;
  font-size: 0.8rem;
}

.size-readout::after { background: var(--accent-deep); }

.sil {
  position: relative;
  z-index: 1;
  display: block;
  filter: drop-shadow(0 6px 8px rgba(29, 26, 23, 0.12));
}

.sil-book, .sil-hand, .sil-tasse { fill: url(#g-neutral); }

.book-spine {
  fill: none;
  stroke: rgba(29, 26, 23, 0.18);
  stroke-width: 2;
}

.sil-figur { fill: url(#g-figur); }

.sil-figur .sil-base { fill: var(--accent-deeper); }

.size-note {
  margin-top: 0.9rem;
  font-size: 0.82rem;
  color: var(--dim);
}

.size-item {
  position: relative;
  height: 100%;
  min-width: 0;
  padding-bottom: 0;
  display: grid;
  grid-template-rows: var(--label-row) minmax(0, 1fr);
  align-items: end;
  justify-items: center;
}

/* The label is taken out of flow so a long caption never widens its
   column and pushes the scene off scale; the column width is the object's
   width and nothing else. */
.size-item .size-label,
.size-item > span:first-child {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  margin: 0;
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
}

.size-item .sil {
  grid-row: 2;
  align-self: end;
  justify-self: center;
  width: auto;
  max-width: none;
}

.sil-book { height: calc(var(--book-cm) * var(--cm)); }
.sil-hand { height: calc(var(--hand-cm) * var(--cm)); }
.sil-tasse { height: calc(var(--tasse-cm) * var(--cm)); }
.sil-figur { height: calc(var(--figur-cm) * var(--cm)); }

/* --obj-w is the object's own rendered width; --foot-w how much of that
   width actually touches the ground; --foot-x where that contact patch
   sits relative to the object's centre (the espresso handle sticks out to
   one side, so the cup body is left of the silhouette's midpoint).

   Both fractions come off the artwork rather than out of the air: sample
   the silhouette's outline, keep the points lying in the lowest 12% of
   its height, and that band is the object's footprint. Its midpoint is
   --foot-x exactly. --foot-w follows the band's span but is allowed to
   read against the body above it, which is why the espresso's is the
   width of the cup rather than of the rounded patch it stands on.

     object     band span   band centre   --foot-w   --foot-x
     Buch         1.000          0          0.98      0
     Figur        1.000          0          0.98      0
     Hand         0.705        +0.050       0.705    +0.05
     Espresso     0.683        -0.127       0.746    -0.127

   The acceptance run recomputes the band centres from the artwork and
   fails if any shadow drifts more than 4% of its object's width off. */
.size-item-book {
  --obj-w: calc(var(--book-cm) * var(--cm) * 0.510638);
  --foot-w: 0.98;
  --foot-x: 0;
}

.size-item-figur {
  --obj-w: calc(var(--figur-cm) * var(--cm) * 0.727273);
  --foot-w: 0.98;
  --foot-x: 0;
}

/* The hand rests on the heel of its palm. The thumb reaches left and
   never touches the ground, so the silhouette's midpoint sits left of
   where the hand actually lands and the shadow trailed off to that side.
   The palm's own band is 0.705 wide and its centre 0.05 to the right. */
.size-item-hand {
  --obj-w: calc(var(--hand-cm) * var(--cm) * 0.670807);
  --foot-w: 0.705;
  --foot-x: 0.05;
}

.size-item-tasse {
  --obj-w: calc(var(--tasse-cm) * var(--cm) * 1.229167);
  --foot-w: 0.746;
  --foot-x: -0.127;
}

.size-item::after {
  content: "";
  position: absolute;
  z-index: 0;
  bottom: 0;
  left: 50%;
  width: calc(var(--obj-w) * var(--foot-w));
  height: calc(var(--obj-w) * var(--foot-w) * 0.19);
  transform: translate(calc(-50% + var(--obj-w) * var(--foot-x)), 45%);
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    rgba(29, 26, 23, 0.22), rgba(29, 26, 23, 0) 72%);
}

/* The figure and its shadow grow together when a size is picked. */
@media (prefers-reduced-motion: no-preference) {
  .sil-figur { transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
  .size-item-figur::after {
    transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1),
                height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .sil-figur, .size-item-figur::after { transition: none; }
}

/* The captions never shrink below 12 px. Narrow phones used to take them
   down to 0.52rem and then 0.47rem, which drew "Buch 21,5 cm" at 7.5 px on a
   390 phone (measured 06.10.2026); both pages had carried their own version
   of that and the numbers differed, so the same scene wore different
   captions depending on which page it stood on.

   At 12 px a one-line caption is wider than the column of the object it
   names once the scene is narrow: "Espresso 7 cm" is about 99 px over a cup
   57 px wide at 390 and 44 px wide at 320, and it would run past the
   stage. Below 540 px of component width each caption therefore breaks
   into name over measure. The measure is joined by a no-break space in
   app/templates/_size_demo.html, so min-content breaks only between the
   two, and the widest line left is "Espresso", about 56 px. The label row
   grows to hold the second line, which makes the stage taller by that
   much and leaves the scale itself alone.

   The trigger is the component's own width, not the viewport's: the same
   bytes stand full width on the landing page and inside the order form's
   column in the Studio, and .size-demo is already the container --cm is
   measured against. */
@container (max-width: 540px) {
  .size-stage { --label-row: 2.75rem; }
  /* specific enough to beat .size-item > span:first-child above */
  .size-stage .size-item > .size-label {
    width: min-content;
    white-space: normal;
    letter-spacing: 0;
  }
  /* The readout's number and unit are separate words in the markup, which
     the acceptance run reads back as "18 cm", so it is held on one line
     here rather than with a no-break space. */
  .size-stage .size-readout > [data-cm] { white-space: nowrap; }
  /* The two edge captions stay centred over their object wherever they fit
     and are held inside the stage where they would not: "Espresso" is 8ch
     over a cup 38 px wide in the Studio's order column on a 320 phone, and
     centred it ran 1.4 px past the stage edge. ch is the caption's own
     monospace advance, so 4ch is half of "Espresso" and 3.5ch half of
     "21,5 cm". */
  .size-stage .size-item-tasse > .size-label {
    left: min(50%, calc(100% + var(--stage-pad) - 4ch - 3px));
  }
  .size-stage .size-item-book > .size-label {
    left: max(50%, calc(3.5ch - var(--stage-pad) + 3px));
  }
  .size-label::after { height: 6px; }
}

/* The chips measured 68x40 and 74x40, under the 44 px floor UX F13 set
   for every other control on a phone. Lifted here rather than in
   figuren.css, because this file is the only stylesheet allowed to style
   the shared control. */
@media (max-width: 860px) {
  .size-btn { min-height: 44px; }
}
