/* Doorway Supermarket — activity styles.
   1em = 1/50th of activity width (set by doorway.js onResize).
   All sizing in em; no px except borders.
*/

/* Shared item-visual scale knobs. Declared at `:root` (not on
   `.sm-screen-layout--shopping`) because the fly-animation clone is
   attached to `document.body` and needs to inherit these vars from
   above the shopping-screen container.

   Each destination sizes its item as `intrinsic × per-target scale`,
   where `intrinsic` = the SVG sprite's natural width/height converted
   to em (via `--sm-natural-w` / `--sm-natural-h` custom props set on
   each img by JS after load — see `applyNaturalSize` in
   `supermarket-render.js`). This preserves relative product sizes
   (small tuna tin renders small, tall loo-roll pack renders tall)
   instead of forcing every sprite into a single square. */
:root {
    /* Three independent sprite scales:
         --sm-fly-item-scale     — flyer in transit (constant during flight)
         --sm-round-item-scale   — resting size in the round-the-price dialog
         --sm-trolley-item-scale — resting size inside the trolley basket
       Declared at :root because the fly-animation clone is attached to
       document.body and needs to inherit these vars from above the
       shopping-screen container. */
    --sm-fly-item-scale:     0.65;
    --sm-round-item-scale:   0.65;
    --sm-trolley-item-scale: 0.65;
}

/* --- Welcome screen image ---
   Layered composition built from Flash sprites in pictures/:
     trolley-empty.svg — trolley body (handle, basket, wheels)
     belt.svg          — conveyor-belt cylinder
     till.svg          — checkout monitor + stand
   Items (item*.svg) are positioned via percent within the scene.
*/

/* Constrained for flow-mode welcome layout: the scene must fit inside
   .dw-welcome-body alongside title group and optional subtitle without
   pushing the subtitle past the sticky footer at typical viewport heights.
   max-height keeps the wide 800:360 strip from monopolising vertical space
   when the viewport is unusually tall. */
.welcome_image {
    width: 100%;
    max-width: 42em;
    max-height: 18em;
    margin: 0 auto;
    pointer-events: none;
}

/* Scene container — all children absolutely positioned within.
   Aspect ratio mirrors Flash welcome region (trolley to belt to till). */
.wimg-scene {
    position: relative;
    width: 100%;
    aspect-ratio: 800 / 360;
    overflow: hidden;
}

/* Belt sprite — wide, thin cylinder sitting roughly mid-height. The belt SVG
   has preserveAspectRatio="none" so we can squash it to a flat strip.
   Drawn first so trolley + till + items render on top. Starts under the
   trolley so the belt visually disappears behind the basket on the left.
   Flash places the belt high in the frame (~50% from the top) so the
   conveyor surface visually carries the carrots/milk above the bottom of
   the scene; raising the belt brings the HTML5 layout into line. */
.wimg-scene .wimg-belt {
    position: absolute;
    left: 35%;
    right: 0;
    top: 32%;
    width: 65% !important;
    height: 22% !important;
    pointer-events: none;
}

/* Trolley sprite — !important needed to override doorway.css rule
   "div.welcome_image img { width:100%; height:100% }". Sits flush against
   the belt on the right so less of the belt is visible on the left side,
   matching the Flash welcome layout. */
.wimg-scene .wimg-trolley {
    position: absolute;
    left: 7%;
    bottom: 0.5%;
    width: 43% !important;
    height: 100% !important;
    object-fit: contain;
    object-position: bottom left;
    pointer-events: none;
}

/* Trolley front rails overlay — separate Flash sprite (sprite_365,
   "trollyFront") whose job is to render the wire rails on the front of
   the basket OVER the items inside, so the items appear to be enclosed
   by the basket. Without this overlay the items float in front of the
   basket wireframe.
   Native sprite aspect 309:244 — landscape (the rails span the basket's
   open front face). Positioned to overlay the basket interior area
   (roughly left 8%-40%, top 30%-65% in scene coords, matching where
   the items sit). z-index 2 sits above .wimg-item (z:1). */
.wimg-scene .wimg-trolley-front {
    position: absolute;
    left: 10.5%;
    top: 17.5%;
    width: 36% !important;
    height: auto !important;
    aspect-ratio: 309 / 244;
    object-fit: contain;
    object-position: top left;
    pointer-events: none;
    z-index: 2;
}

/* Welcome-scene items (basket + on-belt). Sized off intrinsic SVG
   dimensions (published by initWelcomeSpriteSizes → applyNaturalSize)
   so each product renders at its true relative scale. Each per-item
   rule below sets its own width/height calc using an item-specific
   scale factor. */
.wimg-scene .wimg-item {
    position: absolute;
    object-fit: contain;
    pointer-events: none;
    z-index: 1;
}

/* Items inside the trolley basket (positioned over the trolley sprite).
   trolley-empty.svg is a side-view perspective trolley whose basket
   interior in scene-coordinates is roughly:
     left  edge: 11%  (back of basket, slightly left)
     right edge: 36%  (open front of basket, viewer's right)
     top edge:  35%  (rim of basket)
     bottom:    65%  (bottom of basket where items rest)
   Items stack inside, with cereal box upright at the back-left and
   shorter items in front. Beans is parked at the front-left corner
   separated from the noodle/juice cluster. */
.wimg-scene .wimg-beans {
    left: 16%;
    top:  23%;
    width:  calc(var(--sm-natural-w, 3em) * 0.66);
    height: calc(var(--sm-natural-h, 2em) * 0.66);
}
.wimg-scene .wimg-cereal {
    left: 27%;
    top:  15.5%;
    width:  calc(var(--sm-natural-w, 3em) * 0.66);
    height: calc(var(--sm-natural-h, 2em) * 0.66);
}
.wimg-scene .wimg-noodles {
    left: 19%;
    top:  38%;
    width:  calc(var(--sm-natural-w, 3em) * 0.66);
    height: calc(var(--sm-natural-h, 2em) * 0.66);
}
.wimg-scene .wimg-juice {
    left: 27%;
    top:  51%;
    width:  calc(var(--sm-natural-w, 3em) * 0.66);
    height: calc(var(--sm-natural-h, 2em) * 0.66);
}
.wimg-scene .wimg-pepper {
    left: 31.5%;
    top:  36%;
    width:  calc(var(--sm-natural-w, 3em) * 0.67);
    height: calc(var(--sm-natural-h, 2em) * 0.67);
}

/* Items on the conveyor belt. */
.wimg-scene .wimg-carrots {
    left: 47.5%;
    top:  28%;
    width:  calc(var(--sm-natural-w, 3em) * 0.6);
    height: calc(var(--sm-natural-h, 2em) * 0.6);
}
.wimg-scene .wimg-milk {
    left: 69.5%;
    top:  21%;
    width:  calc(var(--sm-natural-w, 3em) * 0.8);
    height: calc(var(--sm-natural-h, 2em) * 0.8);
}

/* Till group — checkout monitor + stand on the right, with the running
   total displayed in the black screen. Flash frame_02.as line 7 sets the
   till display to "£3.79" on the welcome screen. The group sizes match
   the till sprite aspect (298:353) so the price overlay can be positioned
   in percentage units relative to the rendered till.
   Sits above the belt so the monitor head reaches near the title and the
   stand base clears the belt (matching the Flash welcome). z-index above
   the belt/items so the till body overlays them where they meet. */
.wimg-scene .wimg-till-group {
    position: absolute;
    right: 2%;
    bottom: 42%;
    width: 20%;
    aspect-ratio: 298 / 353;
    z-index: 3;
    pointer-events: none;
}

.wimg-scene .wimg-till {
    position: absolute;
    inset: 0;
    width: 100% !important;
    height: 100% !important;
    object-fit: contain;
    pointer-events: none;
}

/* The till sprite (298×353) has its black monitor screen at the very
   top: SVG y=18..59 of 353 ≈ 5%..17% of the sprite's height. Colour is
   white — the LCD readout on the sprite reads clearest against the
   #000 monitor rectangle. */
.wimg-scene .wimg-till-price {
    position: absolute;
    left: 19%;
    top:  5.5%;
    width: 56%;             /* keeps the original centered-at-22%/right:22% box */
    height: 11%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-family: "Courier New", monospace;
    font-weight: bold;
    font-size: 0.9em;
    line-height: 1;
    pointer-events: none;
    white-space: nowrap;
}

/* --- Options form --- */

/* Flash description paragraph at the top of the options panel.
   Sits above the first fieldset, matching the Flash layout. */
.sm-options-description {
    text-align: center;
    margin: 0 0 var(--dw-space-comfy);
    font-style: italic;
}

/* --- Options grid layout --- */

.sm-activity-grid {
    display: flex;
    flex-direction: column;
    gap: var(--dw-space-comfy);
    align-items: start;
}

/* --- Screen layout ---
 *
 * Each sub-screen (shopping / conveyor / payment / receipt) is a two-level
 * wrapper: an outer `.dw-activity-screen.dw-activity-screen--contents` that
 * shows/hides via the shared `[hidden]` / `.hidden_panel` mechanism and is
 * otherwise `display: contents`, and an inner `.sm-screen-layout` that
 * owns the layout mode (grid / flex per variant).
 *
 * The outer div stays because `.dw-activity-screen` in doorway.css sets
 * `display: flex` unconditionally — flattening the two would either force
 * every supermarket sub-screen into flex column, or fight the shared rule
 * with an activity-specific override per variant. `display: contents` on
 * the outer keeps that shared rule out of the layout, and the inner
 * wrapper picks its own mode.
 */

/* Inner layout wrapper — shared box shape for all four sub-screens.
 * Per-variant classes below select the layout mode. */
.sm-screen-layout {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow-y: auto;
    padding: 1.5em var(--dw-space-loose) var(--dw-space-loose);
    gap: var(--dw-space-default);
}

/* Receipt sub-screen — flex-column shell. */
.sm-screen-layout--receipt {
    display: flex;
    flex-direction: column;
}

/* --- Shopping screen layout ---
   Flash: aisle hanging sign at top, three perspective shelves on the right
   (sprite_482), trolley graphic parked bottom-left (sprite_382), round-the-
   price panel top-left over the trolley, "Pick some items" + Checkout at
   bottom-right. Light-cyan background.
*/

/* Shopping sub-screen — grid shell. */
.sm-screen-layout--shopping {
    background: #d6f0ed;
    display: grid;
    /* Widen the left column so the trolley graphic can grow toward the
       shelves and read at a similar visual weight to the Flash version
       (where the trolley dominates the bottom-left quadrant). */
    grid-template-columns: 14em 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "aisle  aisle"
        "side   shelves"
        "footer footer";
    gap: var(--dw-space-snug) var(--dw-space-snug);
    padding: var(--dw-space-snug) var(--dw-space-comfy) var(--dw-space-narrow);
    position: relative;
    /* Clip the trolley sprite's negative-bottom overflow so a touch-drag
       on it can't scroll the whole shopping scene and make tapping the
       shelf items feel imprecise. */
    overflow: hidden;
}

/* --- Aisle navigation (top row) ---
   Centre: the hanging aisle sign (sprite_503) acts as the panel; the aisle
   name is overlaid as text. Sides: the cycling arrows (sprite_498), with the
   right button visually flipped. */

/* Aisle nav row: arrows hug the central sign, and the whole group is shifted
   right so the sign sits roughly central against the shelves (Flash places
   the hanging sign over the shelving unit, not over the trolley). `gap:0`
   because each arrow carries an explicit negative margin pulling it tight
   against the sign (Flash places the arrowheads almost touching the sign
   edges). `padding-left` shifts the entire row right so the sign moves
   toward the shelves. */
.sm-aisle-nav {
    grid-area: aisle;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0;
    padding-left: 19em;           /* push the whole nav past the trolley column */
    /* Sit above `.sm-shelves-wrap` in the stacking order — the shelves
       scale up 10% from bottom-centre and grow into the aisle-row above. */
    position: relative;
    z-index: 2;
}

/* Sign sized to feel visually dominant like the Flash hanging sign.
   Height keeps the green band's aspect; `padding-bottom` lifts the text
   off the rim so it sits inside the green band. */
.sm-aisle-sign {
    position: relative;
    display: flex;
    align-items: flex-end;        /* push name down into the green band, away from hanger top */
    justify-content: center;
    width: 18.9em;
    height: 3.57em;
    padding-bottom: 0.55em;
    /* The sign is purely decorative — no click handler, no interactive
       descendants. Under the current arrow overlap the prev arrow sits
       inside the sign's visual box; since the sign paints on top of it
       (later DOM sibling in the same stacking context), clicks would
       land here and never reach the arrow. Pointer-events:none lets
       those clicks pass through to the arrow beneath. */
    pointer-events: none;
}

.sm-aisle-sign-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    pointer-events: none;
}

.sm-aisle-name {
    position: relative;
    z-index: 1;
    /* Sized to fit the longest aisle name ("3. Chilled Food") inside the
       painted green band of the hanging sign without wrapping. Flash text
       is regular weight (not bold). */
    font-size: 1em;
    margin: 0;
    font-weight: normal;
    color: #205313;
    white-space: nowrap;
}

.sm-nav-btn {
    background: transparent;
    border: 0.12em solid transparent;
    border-radius: 0.4em;
    padding: var(--dw-space-tight);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3em;
    height: 2.4em;
    transform: translateY(0.85em);
}

/* Pull each arrow tight against the hanging sign — Flash places the
   arrowheads almost touching the sign edges. Negative margin overlaps the
   transparent SVG padding into the sign's frame so the visible arrowhead
   sits next to the sign at ~0.2em from the visible edge. */
.sm-aisle-nav .sm-nav-btn-prev {
    margin-right: -4.65em;
    /* Shift the whole {prev, sign, next} group right — sign and next
       flex-flow after prev, so the visible gap on each side of the sign
       stays symmetric. */
    margin-left: 5.3em;
}
.sm-aisle-nav .sm-nav-btn-next {
    margin-left: -4.65em;
}

/* `.sm-nav-btn { display: flex }` comes later than the shared
   `.hidden_panel { display: none }` and has equal specificity, so it would
   otherwise win and leave both aisle arrows visible on the first/last shelf.
   Force display:none with `visibility:hidden` to also reserve layout space
   (the centre sign stays centred when one arrow disappears). */
.sm-nav-btn.hidden_panel {
    display: flex;
    visibility: hidden;
}

.sm-nav-btn img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.sm-nav-btn-next img {
    transform: scaleX(-1);
}

/* Keyboard focus uses the uniform dotted-black + z-elevation rule near
   the top of the file (`.sm-nav-btn:focus-visible` in the shared group).
   No local override needed here — the hover cue is the icon brightness
   filter below. */

@media (hover: hover) {
    .sm-nav-btn:hover img {
        filter: brightness(1.1);
    }
}

/* --- Shelves wrap (right) ---
   The Flash shelves sprite is the backdrop. We overlay items in a 3×4 grid
   that aligns to the shelf perspective. The sprite viewBox is 504.45 ×
   551.7; items occupy roughly y=18..96% inside it, three horizontal bands.
*/

/* The wrap matches the shelves sprite's aspect ratio (504.45 × 551.7) so the
   inset-percentage grid below aligns to the painted shelf surfaces — without
   this, the SVG centres inside a wider container and items drift off-shelf. */
.sm-shelves-wrap {
    grid-area: shelves;
    position: relative;
    min-height: 0;
    aspect-ratio: 504 / 552;
    height: 100%;
    margin: 0 auto;
    /* Visually scale the whole shelving unit + products + tags by 10%
       and drop the whole thing down by about half an arrow-button
       height (arrow is 2.4em → 1.2em drop) so the shelves don't crowd
       the aisle sign above. Uses transform so layout footprint stays
       put (sign above / trolley beside are unaffected). Origin at
       bottom-centre keeps the visual growth going upward + outward.
       Transform order: scale is applied first (right-to-left), then
       translate — so the whole scaled unit shifts down by 1.2em. */
    transform: translateY(1.2em) scale(1.1);
    transform-origin: bottom center;
    max-width: 100%;
}

.sm-shelves-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

/* The shelves sprite has perspective: the painted "shelf surface" occupies the
   centred ~62% width within the sprite frame, with depth/angle on the right.
   `.sm-item-grid` constrains items to that visible surface so the 4th item per
   row doesn't fall off into the perspective.

   The bottom inset is intentionally tight (≈2%) so items land directly on the
   bottom shelf surface — Flash places items/price-tags right at the shelf
   edge with no air gap below. The grid is divided into three equal-height
   row bands, each anchored to the bottom of its band so its contents sit on
   the shelf line for that row. */
.sm-item-grid {
    position: absolute;
    inset: 5% 18% 2% 6%;
    display: flex;
    flex-direction: column;
    gap: 0;
    pointer-events: none;        /* let the backdrop show through; buttons re-enable */
}

/* Price-tag overlay: mirrors .sm-item-grid geometry exactly and sits above
   it in the shelves-wrap stacking context. Each .sm-shelf-row inside
   .sm-item-grid establishes its own stacking context via `transform`, so
   a tag inside a row's own button was trapped inside that row — a
   neighbouring row's tall product would paint over the row-above's tags.
   Hoisting tags into this parallel layer at z-index:3 puts them above
   every product image regardless of which row they belong to.
   Populated by supermarket-render.js in lockstep with the item grid. */
.sm-tag-layer {
    position: absolute;
    inset: 5% 18% 2% 6%;
    display: flex;
    flex-direction: column;
    gap: 0;
    pointer-events: none;
    z-index: 3;
}

/* Empty cell that holds a single `.sm-item-price`. Acts as the price-tag's
   positioning container: the tag is absolutely positioned at
   `bottom: -1.2em; left: 50%;` inside this cell, so the cell needs
   `position: relative`. The row's `align-items: end` bottom-aligns the
   cell to the shelf line so the tag lands at `shelf-line - 1.2em`. */
.sm-tag-cell {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: end;
}

/* Shelves are drawn in perspective with the left edge slightly higher than
   the right (vanishing point off-right). Each row of four items sits along
   that perspective line — items further right drop down by an amount
   proportional to the per-row `--row-tilt` set below, expressed as the total
   drop between the leftmost and rightmost item. Items themselves stay
   upright — the row's tilt is realised as `translateY` per column position,
   NOT as a rotate on the row (matching Flash, where products sit upright
   on a sloped shelf surface).
   `padding-bottom` reserves breathing room at the bottom of each row band
   so products don't butt up against the shelf line below them.
   `align-items: end` bottom-aligns items within the row so taller and
   shorter products both rest on the shelf line (plus the tilt).
   Mid and bot rows shift UP (via their per-nth-child translate) so they
   read as further away in the perspective backdrop. */
.sm-shelf-row {
    --row-tilt: 0em;          /* overridden per-row below */
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1.15em;
    flex: 1;
    min-height: 0;
    align-items: end;
    position: relative;
    padding-bottom: 1.4em;
}

/* Per-shelf vertical shift + tilt magnitude.
   Each shelf in the SVG backdrop is drawn at a slightly different
   perspective angle (top nearly flat, bottom drops most); the product
   row's --row-tilt encodes the total L→R drop for that row and
   --row-tag-tilt rotates its price tags to track the same perspective.
   --row-tag-line-delta is (tag-line-tilt − row-tilt) — non-zero values
   let the tag row tilt independently of the products above.
   Mid and bot rows shift UP (negative Y translate) so their price-tag
   strip clips onto the green shelf-rim painted higher in the SVG
   backdrop — Flash places mid-shelf tags ≈ half a label-height higher
   and bottom-shelf tags ≈ a full label-height higher than naive even
   spacing. */
.sm-shelf-row:nth-child(1) {
    --row-tilt: 0.35em;
    --row-tag-tilt: 1.5deg;
    --row-tag-line-delta: -0.05em;
    --row-tag-y-offset: 0.7em;
    transform: translate(0.1em, 0em);
}
.sm-shelf-row:nth-child(2) {
    --row-tilt: 1.05em;
    --row-tag-tilt: 5.5deg;
    --row-tag-line-delta: 0.2em;
    --row-tag-y-offset: 0.55em;
    transform: translate(0.1em, -1.25em);
}
.sm-shelf-row:nth-child(3) {
    --row-tilt: 2em;
    --row-tag-tilt: 8.5deg;
    --row-tag-line-delta: -0.2em;
    --row-tag-y-offset: 0.95em;
    transform: translate(-0.3em, -3.05em) rotate(-0.5deg);
}

/* Per-column drop, scaled by the current row's `--row-tilt` (the total drop
   from leftmost to rightmost item). Items stay upright.  The `--col-frac`
   var (0, 0.333, 0.667, 1.0) is reused below by `.sm-item-price` to slide
   its tag independently along the shelf's tag-line tilt.
   Uses `top` (with `position: relative`) instead of `transform: translateY`
   so the button doesn't establish its own stacking context (which would
   trap the price tag inside).
   Applied identically to `.sm-tag-cell` in the parallel tag-layer so tag
   positions track their buttons' column drop. */
.sm-shelf-row > .sm-item-btn:nth-child(1),
.sm-shelf-row > .sm-tag-cell:nth-child(1)  { --col-frac: 0;     top: 0; }
.sm-shelf-row > .sm-item-btn:nth-child(2),
.sm-shelf-row > .sm-tag-cell:nth-child(2)  { --col-frac: 0.333; top: calc(var(--row-tilt) * 0.333); }
.sm-shelf-row > .sm-item-btn:nth-child(3),
.sm-shelf-row > .sm-tag-cell:nth-child(3)  { --col-frac: 0.667; top: calc(var(--row-tilt) * 0.667); }
.sm-shelf-row > .sm-item-btn:nth-child(4),
.sm-shelf-row > .sm-tag-cell:nth-child(4)  { --col-frac: 1;     top: var(--row-tilt); }

/* The button wraps just the product image; the price tag is absolutely
   positioned below it on the green shelf rim painted in the SVG backdrop.
   No `height: 100%` — the click target hugs the visible product image
   rather than the whole row band.
   The resting 1.44 shelf bump lives on the button (not the child img) so
   the button's border-box matches the visual sprite extent. `outline` is
   painted at the border-box, so with the transform here the dotted focus
   ring wraps what the user sees. `--sm-shelf-hover-scale` composes the
   mouse-hover 1.08 bump on top; transform-origin center bottom anchors
   the sprite to the shelf line as the button scales. */
.sm-item-btn {
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1em;
    gap: 0;
    position: relative;
    --sm-shelf-hover-scale: 1;
    transform: scale(1.44) scale(var(--sm-shelf-hover-scale));
    transform-origin: center bottom;
    transition: transform 0.15s ease-out;
}

/* Three distinct hover/focus/scan affordances so mouse, keyboard and
   switch users each get an unambiguous cue:
     - :hover           — subtle white glow + scale-up composed via
                          `--sm-shelf-hover-scale` (mouse pointer), matching
                          the round-the-price dialog's item hover (see
                          .sm-round-itemslot-btn). Hugs the sprite silhouette
                          via drop-shadow filters on the child <img>.
     - :focus-visible   — standard Doorway dotted-black outline on the
                          button box (see shared/doorway.css). Rectangular
                          around the button's bounding rect, not the sprite
                          silhouette — CSS `outline` can't follow alpha
                          edges, and the SVG-filter route to trace dashes
                          around an alpha ring produces uneven spacing on
                          organic shapes. Matches every other keyboard-focus
                          ring in the project (add-and-subtract block
                          buttons, about-time cards, shared toolbar).
     - .scan_highlight  — shared two-tone shape-hug filter (switch scan,
                          defined below): orange bloom + white outer halo
                          traced around the sprite silhouette.
   Suppress the global button:hover translucent background (doorway.css)
   so nothing else paints behind the sprite. */
.sm-item-btn:focus-visible {
    outline: 0.2em dotted black;
    outline-offset: 0.15em;
    background: transparent;
    /* Elevated with the uniform non-money focus rule below; kept explicit
       here so a shelf item's outline sits above neighbouring row
       stacking contexts (each `.sm-shelf-row` transforms itself into its
       own layer). */
    position: relative;
    z-index: 25;
}
.sm-item-btn:focus {
    background: transparent;
}
@media (hover: hover) {
    .sm-item-btn:hover {
        background: transparent;
    }
}

/* Uniform keyboard-focus treatment for every non-money interactive button
   in the supermarket activity: shelf/trolley/round-dialog product buttons,
   aisle-nav arrows, stepper +/−, and the pencil/main nav buttons that live
   inside the supermarket screens (Checkout, Next, Done, Print, Repeat,
   Home). Matches the shared Doorway dotted focus ring (0.2em black),
   deliberately identical to `.sm-item-btn:focus-visible` above so every
   button on the activity reads with the same affordance.
   `position: relative; z-index: 25` lifts the focused button above
   neighbouring UI (till sprite z:3-10, hand money z:8, wallet peeks z:3-7,
   till total reveal z:20) so the dotted outline isn't clipped by an
   overlapping sibling or a sibling stacking context. 25 sits comfortably
   below the round-overlay dialog (z:100) and the fly-item overlay (z:1000)
   so a focus ring on a background button can't paint through a modal.
   Money buttons (`.sm-money-btn`, `.sm-change-cluster-btn`) are excluded
   intentionally — their bespoke yellow drop-shadow glow (see rules further
   down) hugs the coin/note alpha edge, which is a more useful cue than a
   rectangular outline around the invisible bounding box. */
.sm-nav-btn:focus-visible,
.sm-trolly-item-btn:focus-visible,
.sm-round-itemslot-btn:focus-visible,
.sm-stepper-btn:focus-visible,
.sm-screen .pencil_btn:focus-visible,
.sm-screen .main_button:focus-visible {
    outline: 0.2em dotted black;
    outline-offset: 0.15em;
    position: relative;
    z-index: 25;
}

/* Shelf-item hover: bump `--sm-shelf-hover-scale` on the button so the
   `transform: scale(1.44) scale(var(...))` composition on `.sm-item-btn`
   above resolves to 1.44 × 1.08 ≈ 1.55. Halo drop-shadow stays on the
   child img so the glow hugs the sprite silhouette. */
@media (hover: hover) {
    .sm-item-btn:hover {
        --sm-shelf-hover-scale: 1.08;
    }
    .sm-item-btn:hover img {
        filter: drop-shadow(0 0 0.2em rgba(255, 255, 255, 0.9))
                drop-shadow(0 0 0.1em rgba(255, 255, 255, 0.8));
    }
}

/* Shape-hugging scan-ring for transparent-alpha product sprites via the
   shared `--dw-scan-shape-hug-filter` (shared/doorway.css): orange bloom
   over the sprite plus a white outer halo that lifts dark products off
   the shelf backdrop. Applied to the row group too so 2-switch scan-
   into-group glows every visible item rather than boxing the row band.
   The shared rectangular `box-shadow` ring is suppressed because each
   `.sm-shelf-row` establishes its own stacking context via `transform`,
   so a rectangular ring around one row's item would be clipped by
   neighbouring rows. */
.sm-item-btn.scan_highlight,
.sm-shelf-row.scan_highlight {
    box-shadow: none;
    filter: var(--dw-scan-shape-hug-filter);
}

/* Product sprite sizing — Flash shelves show noticeably larger product
   graphics than the shared HTML5 baseline.
   `object-position: center bottom` anchors the actual graphic to the
   bottom of the fixed-height img box, so short/squat products (e.g. a
   tuna tin) sit on the shelf line instead of centring vertically inside
   the 2.75em box and appearing to float. */
.sm-item-img {
    width: 100%;
    max-width: 3.75em;
    height: 2.75em;
    object-fit: contain;
    object-position: center bottom;
}

/* Green price-tag strip — Flash renders it floating ON the green shelf
   rim painted in the shelves backdrop, with each row's tags clinging to
   the bottom of the row band, BELOW the product image (the item is above
   the tag with a clear gap, not overlapping it). Absolutely positioned
   below the item-btn so the button's hover/click target wraps just the
   product image, not the tag. `bottom:-1.2em` pushes the tag down onto
   the green shelf-rim painted into the SVG backdrop.
   The tag reads --row-tag-tilt (rotation), --row-tag-line-delta (extra
   translateY per column, scaled by --col-frac 0..1), and --row-tag-y-offset
   (rigid drop) — all set on the parent .sm-shelf-row:nth-child(N) above.
   The translateY here is the *delta* from the product row's tilt, so when
   --row-tag-line-delta is 0 AND --row-tag-y-offset is 0 the tag row sits
   directly under the products; otherwise the tag row tracks its own
   perspective line and/or slides up/down as a unit. */
.sm-item-price {
    position: absolute;
    bottom: -1.2em;
    left: 50%;
    transform: translate(-50%, calc(var(--row-tag-line-delta, 0em) * var(--col-frac, 0) + var(--row-tag-y-offset, 0em)))
               rotate(var(--row-tag-tilt, 0deg));
    transform-origin: center center;
    font-size: 0.88em;
    color: #0c4e0c;
    font-weight: bold;
    background: #ffffff;
    border: 0.14em solid #000;
    border-radius: 0;
    /* Tag height ≈ font-line + 2 × border + 2 × 0.06em vertical padding
       ≈ 1.28em, so the price sits comfortably inside the label. */
    padding: 0.06em var(--dw-space-snug);
    min-width: 2.4em;
    text-align: center;
    box-shadow: 0 0.05em 0 #c8e8c0;
    z-index: 2;
    pointer-events: none;       /* clicks pass through to the button */
    white-space: nowrap;
}

/* --- Trolley + round overlay column (left side) --- */

/* --- Round-price overlay ---
   Flash positions the round panel top-left (over the trolley area). Snap it
   into the left grid column with absolute positioning so it overlays the
   trolley while open. */

.sm-round-overlay {
    position: absolute;
    top: 3em;
    left: 0.8em;
    width: 13em;
    background: #c4ebbc;
    border: 0.18em solid #205313;
    border-radius: 0.4em;
    padding: 0.7em;
    z-index: 100;
    text-align: center;
    box-shadow: 0 0.2em 0.6em rgba(0,0,0,0.25);
}

.sm-round-overlay h3 {
    font-size: 1em;
    margin: 0 0 var(--dw-space-narrow) 0;
    color: #205313;
    line-height: 1.2;
}

/* Drop-target slot for the flying product sprite. Sits in the right-hand
   column of .sm-round-body next to the £0 / − + / Add controls. Reserves
   its full 4em × 4em box even when empty so the overlay layout doesn't
   jump when the flyer lands or the item is returned. Fixed (not min) so
   an arriving flyer can't push the overlay wider or taller; oversized
   items are contained via the img rules below.
   `.sm-round-itemslot-filled` is retained as a JS state marker; it does
   not change the slot's dimensions. */
.sm-round-itemslot {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width:  4em;
    height: 4em;
    overflow: visible;
}

/* Button wrapper stretches to fill the reserved slot so the img inside
   can measure its max-width/max-height against a definite parent. */
.sm-round-itemslot > .sm-round-itemslot-btn {
    width:  100%;
    height: 100%;
    /* Flex-center the img so the resting position matches exactly what
       the flyer aimed at (slot centre). Without this, `margin: auto` on
       a block img only centres horizontally, and tall/short products
       would rest visibly off-centre from the flyer's landing point. */
    display: flex;
    align-items: center;
    justify-content: center;
}

.sm-round-itemslot img {
    /* Render at each product's natural aspect × round-item-scale, but
       clamp to the reserved slot box so the overlay geometry stays put
       whichever product lands (tuna small, cornflakes tall). Centering
       is done by the flex button wrapper above. */
    display: block;
    max-width:  100%;
    max-height: 100%;
    width:  calc(var(--sm-natural-w, 3em) * var(--sm-round-item-scale));
    height: calc(var(--sm-natural-h, 2em) * var(--sm-round-item-scale));
    object-fit: contain;
}

/* The just-placed product sprite is wrapped in a button so clicking it
   returns the item (cancels the round-the-price step). Style as a plain
   image well — no chrome — with a hover/focus ring so users discover the
   click target. */
.sm-round-itemslot-btn {
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    border-radius: 0.3em;
    transition: transform 0.15s ease-out;
}

/* Hover/focus bump lives on the button (not the child img) so the
   button's border-box grows with the sprite. The uniform dotted focus
   ring further up is painted at that border-box, so it wraps the
   enlarged sprite instead of sitting inside it. */
.sm-round-itemslot-btn:focus-visible {
    transform: scale(1.08);
}
@media (hover: hover) {
    .sm-round-itemslot-btn:hover {
        transform: scale(1.08);
    }
}

/* Fade-in applied via JS each time the overlay is revealed (Flash used
   a 0.5s alpha tween: `fadeIn("roundMenu", true)`). Decorative — the
   overlay text and spoken `round-prompt` audio carry the meaning. Only
   opacity is animated (not transform: scale) because flyItem captures
   the item-slot's rect at animation-start and would otherwise land at
   the scale-0.85 position while the item's resting spot is at scale 1. */
.sm-round-overlay-enter {
    animation: sm-round-overlay-enter 0.35s ease-out;
}

@keyframes sm-round-overlay-enter {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* 3-column × 2-row grid:
     Row 1: [£0 spanning cols 1-2] [item in col 3]
     Row 2: [ − ]                  [ + ] [Add in col 3]
   This anchors £0 centrally over the − + stepper pair and the item slot
   centrally over the Add button. Matches the Flash layout where the
   current rounded value sits directly above the − and + steppers, with
   the item indicator sitting above the Add pencil. */
.sm-round-body {
    display: grid;
    grid-template-columns: auto auto auto;
    grid-template-rows: auto auto;
    justify-items: center;
    align-items: center;
    gap: var(--dw-space-snug) var(--dw-space-default);
    margin: var(--dw-space-snug) 0 var(--dw-space-tight) 0;
    justify-content: center;
}
#smRoundNum      { grid-column: 1 / span 2; grid-row: 1; }
#smRoundItemSlot { grid-column: 3;          grid-row: 1; }
#smRoundMinus    { grid-column: 1;          grid-row: 2; }
#smRoundPlus     { grid-column: 2;          grid-row: 2; }
#smRoundAdd      { grid-column: 3;          grid-row: 2; }

/* Nudge the stepper row down slightly relative to the £0 / item-slot
   row above so the buttons don't crowd the numeric readout. */
#smRoundMinus,
#smRoundPlus,
#smRoundAdd {
    margin-top: 0.4em;
}

.sm-stepper-btn {
    font-size: var(--dw-font-size-large);
    width:  1.6em;
    height: 1.6em;
    border: 2px solid var(--dw-color-text-strong);
    /* Square with only slightly rounded corners — matches .sm-round-add so
       the three buttons on this row read as a set. */
    border-radius: 0.15em;
    cursor: pointer;
    background: #f0f0f0;
    padding: 0;
    line-height: 1;
}

/* "Add" button shares the stepper row in Flash — sized to match the
   stepper's font size and 1.6em box height so the three row-2 buttons
   read as a set. Flex-centres the label so its baseline sits on the
   button's centreline instead of drifting with the default line-height. */
.sm-round-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--dw-font-size-large);
    height: 1.6em;
    padding: 0 0.7em;
    margin: 0;
    border-radius: 0.15em;
    line-height: 1;
}

/* Keyboard focus (`.sm-stepper-btn:focus-visible`) uses the uniform
   dotted-black + z-elevation rule near the top of the file; the
   background flash below is a shared hover/focus tint. */
.sm-stepper-btn:focus-visible {
    background: var(--dw-color-border-faint);
}
@media (hover: hover) {
    .sm-stepper-btn:hover {
        background: var(--dw-color-border-faint);
    }
}

.sm-round-value {
    font-size: 1.6em;
    font-weight: bold;
    min-width: 2em;
    padding: 0 var(--dw-space-snug);
    text-align: center;
    background: #fff;
    border: 0.1em solid #205313;
    border-radius: 0.2em;
    color: #205313;
}

.sm-round-feedback {
    color: var(--dw-color-feedback-wrong);
    font-size: 1em;
    min-height: 1.4em;
    margin: var(--dw-space-snug) 0;
}

/* --- Trolley (left column on shopping screen) ---
   Flash uses a perspective trolley sprite (sprite_382) parked bottom-left.
   We use it as a backdrop; the list of collected items overlays the basket.
*/

.sm-trolly-area {
    grid-area: side;
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: stretch;
    min-height: 0;
    padding: 0;
}

.sm-trolly-bg {
    position: absolute;
    left: -0.5em;
    bottom: -4em;
    /* Grow the trolley so it visually dominates the bottom-left quadrant
       (matching Flash) rather than being a small thumbnail. */
    width: 126%;
    height: 100%;
    object-fit: contain;
    object-position: bottom left;
    pointer-events: none;
    z-index: 0;
}

/* Front wire rails overlay (Flash sprite_365 "trollyFront", attached in
   frame_05.as:273 at high depth 999000 → 900000 after items land, so it
   always renders on top of the trolley contents). Sits over the basket's
   open front so items in .sm-trolly-list look enclosed by the rails
   rather than floating in front of the basket wireframe. */
.sm-trolly-front {
    position: absolute;
    left: 6%;
    top: 37%;
    width: 115.5%;
    height: auto;
    aspect-ratio: 309 / 244;
    object-fit: contain;
    pointer-events: none;
    z-index: 2;
}

.sm-trolly-heading {
    margin: 0;
}

/* Items in the basket — laid out as 10 absolutely-positioned slots inside
   the basket opening of the trolley SVG. No panel chrome (no background,
   no border) — Flash drops items straight into the basket so the trolley
   graphic does the visual work.
   Slots follow a 3-2-3-2 pattern: rows 1 and 3 hold 3 items each,
   rows 2 and 4 hold 2 items nested between them. Row Y positions are
   integer multiples of --slot-row-step; each successive row is shifted
   right by an extra --slot-slant-x, producing the diagonal `\` bias that
   tracks the trolley basket's painted perspective. --slot-col-step is the
   horizontal spacing between adjacent columns. Per-slot --slot-x/--slot-y
   values are set by the :nth-child rules below. */
.sm-trolly-list {
    list-style: none;
    padding: 0;
    margin: 0;
    position: absolute;
    left:   23.5%;
    right:  0%;
    top:    48.5%;
    bottom: 21%;
    z-index: 1;
    overflow: visible;
    --slot-col-step: 32%;
    --slot-row-step: 25.5%;
    --slot-slant-x:  7.4%;
}

.sm-trolly-item {
    position: absolute;
    left: var(--slot-x, 0);
    top: var(--slot-y, 0);
    /* Fixed reserved size — keeps an empty slot's bounding rect identical
       to a filled slot's, so the fly animation aims at the slot's centre
       pre-population without a diagonal snap when the img actually lands.
       Matches .sm-round-itemslot for basket-geometry consistency. */
    width:  4em;
    height: 4em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Row spacing (--slot-row-step) is tighter than the 4em slot height,
       so neighbouring rows visually overlap. The <li> passes clicks
       through; the inner <button> (auto-sized to its img) intercepts
       them, so the click target hugs the sprite instead of covering the
       row below. */
    pointer-events: none;
}

/* Per-slot positioning — 10 slots in a 3-2-3-2 pattern. Columns for
   even-numbered rows (2 slots) sit at half-step offsets so they nest
   between the odd rows' 3 slots. Y positions are integer multiples of
   --slot-row-step; X positions accumulate slant as row index grows. */
/* Row 1 (y=0): 3 slots at columns 0, 1, 2. */
.sm-trolly-item:nth-child(1)  { --slot-x: 0;
                                --slot-y: 0; }
.sm-trolly-item:nth-child(2)  { --slot-x: var(--slot-col-step);
                                --slot-y: 0; }
.sm-trolly-item:nth-child(3)  { --slot-x: calc(var(--slot-col-step) * 2);
                                --slot-y: 0; }
/* Row 2 (y=1×row): 2 slots at columns 0.5, 1.5 + 1 slant. */
.sm-trolly-item:nth-child(4)  { --slot-x: calc(var(--slot-col-step) * 0.5 + var(--slot-slant-x));
                                --slot-y: var(--slot-row-step); }
.sm-trolly-item:nth-child(5)  { --slot-x: calc(var(--slot-col-step) * 1.5 + var(--slot-slant-x));
                                --slot-y: var(--slot-row-step); }
/* Row 3 (y=2×row): 3 slots at columns 0, 1, 2 + 2 slant. */
.sm-trolly-item:nth-child(6)  { --slot-x: calc(var(--slot-slant-x) * 2);
                                --slot-y: calc(var(--slot-row-step) * 2); }
.sm-trolly-item:nth-child(7)  { --slot-x: calc(var(--slot-col-step) + var(--slot-slant-x) * 2);
                                --slot-y: calc(var(--slot-row-step) * 2); }
.sm-trolly-item:nth-child(8)  { --slot-x: calc(var(--slot-col-step) * 2 + var(--slot-slant-x) * 2);
                                --slot-y: calc(var(--slot-row-step) * 2); }
/* Row 4 (y=3×row): 2 slots at columns 0.5, 1.5 + 3 slant. */
.sm-trolly-item:nth-child(9)  { --slot-x: calc(var(--slot-col-step) * 0.5 + var(--slot-slant-x) * 3);
                                --slot-y: calc(var(--slot-row-step) * 3); }
.sm-trolly-item:nth-child(10) { --slot-x: calc(var(--slot-col-step) * 1.5 + var(--slot-slant-x) * 3);
                                --slot-y: calc(var(--slot-row-step) * 3); }

/* Transient "flyer" — a cloned item sprite that animates from a shelf
   button to the round-overlay item slot (on click) and from there into
   the specific trolley slot cell the item is about to occupy (on Add).
   Mounted on document.body and removed on transitionend; uses fixed
   positioning so its coordinates aren't warped by ancestor transforms. */
.sm-fly-item {
    position: fixed;
    pointer-events: none;
    z-index: 1000;
    will-change: transform, opacity;
    /* Rendered at natural × --sm-fly-item-scale, constant across the
       whole translate — no scale animation, so the flyer neither grows
       nor shrinks in flight. On landing the flyer is removed and the
       destination img (trolley slot / round-dialog slot) paints at
       its own resting scale in its place. */
    width:  calc(var(--sm-natural-w, 3em) * var(--sm-fly-item-scale));
    height: calc(var(--sm-natural-h, 2em) * var(--sm-fly-item-scale));
}

.sm-fly-item-go {
    transition: transform 0.4s ease-out, opacity 0.4s ease-out;
}

/* Clickable wrapper inside each slot — bare button restyled to look like
   the bare image it replaces. Clicking returns the item to the shelf
   (Flash frame_05.as:435–469 newItem<N>.onRelease). */
.sm-trolly-item-btn {
    /* Auto-size to the img content (not 100% of slot) so the click target
       hugs the sprite. Combined with pointer-events: none on the parent
       slot, users can only click the visible product, not the empty slot
       area — which prevents neighbouring rows from stealing clicks where
       row_step is tighter than the slot box. */
    width:  auto;
    height: auto;
    padding: 0;
    margin: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    pointer-events: auto;
}

/* Hover feedback matches the shelf items and the round-the-price dialog:
   subtle white glow around the sprite silhouette + scale(1.08) so mouse
   users get consistent affordance across all three item surfaces (shelf,
   trolley, rounding dialog). Halo drop-shadow stays on the child img so
   it hugs the sprite alpha; the scale bump lives on the button so its
   border-box grows with the sprite, letting the uniform dotted focus
   ring (further up) wrap the enlarged silhouette rather than paint at
   the smaller un-scaled box. Keyboard focus keeps outline + z-elevation
   with no scale — tab position stays visually distinct. */
.sm-trolly-item-btn {
    transition: transform 0.15s ease-out;
}
@media (hover: hover) {
    .sm-trolly-item-btn:hover {
        transform: scale(1.08);
    }
    .sm-trolly-item-btn:hover img {
        filter: drop-shadow(0 0 0.2em rgba(255, 255, 255, 0.9))
                drop-shadow(0 0 0.1em rgba(255, 255, 255, 0.8));
    }
}

/* Keyboard focus (`.sm-trolly-item-btn:focus-visible`) uses the uniform
   dotted-black + z-elevation rule near the top of the file. */

/* Same shape-hugging scan-ring override as the shelf items — the
   trolley sprite has transparent alpha and the ring should trace it,
   not the surrounding slot cell. Applied to the trolley list group too
   so 2-switch scan-into-group traces the item silhouettes in the basket
   rather than painting a rectangle around the whole UL box. */
.sm-trolly-item-btn.scan_highlight,
.sm-round-itemslot-btn.scan_highlight,
.sm-trolly-list.scan_highlight {
    box-shadow: none;
    filter: drop-shadow(0 0 0.25em #ff8800)
            drop-shadow(0 0 0.15em #ff8800)
            drop-shadow(0 0 0.1em  #ff8800);
}

/* Product sprite inside the basket — rendered at the sprite's own
   intrinsic aspect × trolley-scale (see `applyNaturalSize`). */
.sm-trolly-img {
    /* Clamped to the fixed slot box so oversize sprites don't push the
       slot's visual centre away from the flyer's target. */
    max-width:  100%;
    max-height: 100%;
    width:  calc(var(--sm-natural-w, 3em) * var(--sm-trolley-item-scale));
    height: calc(var(--sm-natural-h, 2em) * var(--sm-trolley-item-scale));
    object-fit: contain;
    flex-shrink: 0;
}

/* Trolley total — Flash didn't render an on-screen total on the shopping
   screen, just the items in the basket. Keep the element for screen
   readers but visually hide it via the standard sr-only pattern.
   `!important` overrides the high-specificity ID rules earlier in this
   stylesheet. */
.sm-trolly-total {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* --- Screen navigation ---
   Bottom-right placement everywhere; on the shopping screen the parent grid
   places this row in the "footer" area alongside the "Pick some items" hint.
*/

.sm-screen-nav {
    display: flex;
    gap: var(--dw-space-loose);
    justify-content: flex-end;
    align-items: center;
    margin-top: auto;
    padding-top: var(--dw-space-snug);
}

#smShoppingScreen .sm-shopping-footer {
    grid-area: footer;
    justify-content: flex-end;
    align-items: center;
    gap: var(--dw-space-comfy);
    /* Reserve vertical space for the Checkout button so showing/hiding it
       (during round-the-price overlay) doesn't reflow the grid above. */
    min-height: 2.6em;
}

/* Reserve layout space for the Checkout button. Using visibility:hidden
   instead of display:none keeps the button slot in flow so the grid above
   doesn't reflow up and down each time the round-overlay opens/closes. */
.sm-shopping-next.hidden_panel {
    display: inline-block;
    visibility: hidden;
}

.sm-shopping-hint {
    margin: 0;
    text-align: center;
    font-style: italic;
    font-weight: bold;
    color: var(--dw-color-text-secondary);
    background: #fff;
    border: 0.12em solid var(--dw-color-border-muted);
    border-radius: 0.4em;
    padding: var(--dw-space-tight) var(--dw-space-comfy);
}

/* --- Conveyor screen ---
   Flash: pale cyan background, dark grey 3D belt cylinder spanning the
   bottom half, till on the right (above belt surface), simple orange
   item-dots rolling left along the belt.
*/

/* Conveyor sub-screen — block shell. The outer .sm-conveyor-screen class is
 * retained as a semantic marker for other selectors downstream. */
.sm-screen-layout--conveyor {
    background: #e0f7f5;
    /* Conveyor scene fills the screen — no flex column, the scene is the
       sole positioned context for belt, till, items, text, and Next button. */
    display: block;
    position: relative;
    overflow: hidden;
    padding: 0;
    gap: 0;
}

.sm-conveyor-scene {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

/* Estimate + till-total text block — right-aligned lines in the
   upper-middle of the stage. Mirrors Flash frame_06: "You estimated £N"
   sits on top, "The total is £N" fades in below once scanning completes.
   The mid-scan running total is a *separate* element (.sm-till-pending)
   that overlays the till's monitor screen — see below. */
.sm-conveyor-text-block {
    position: absolute;
    top: 4em;
    right: 4em;
    text-align: right;
    z-index: 5;             /* above the belt, below the till sprite */
    pointer-events: none;
}

.sm-estimate-text,
.sm-till-total {
    margin: 0;
    font-size: 1.6em;
    line-height: 1.4;
    color: var(--dw-color-text-primary);
    white-space: nowrap;
}

.sm-till-total {
    min-height: 1.4em;       /* reserve a line so the layout doesn't jitter
                                between empty state and the final reveal */
}

/* Running till total: overlaid on the till sprite's black monitor
   screen while items are being scanned; stays up through the final
   summary so the on-till value is always visible. Also reused on the
   payment screen (.sm-payment-scene) so the total still reads on the
   till while the cashier asks for it. Position lands on the till
   screen at the current till size/position. */
.sm-till-pending {
    position: absolute;
    left: 22.6em;
    top:  8.45em;
    width: 10em;
    margin: 0;
    font-size: 1.4em;
    line-height: 1;
    color: #ffffff;
    text-align: center;
    white-space: nowrap;
    z-index: 15;             /* above the till sprite (z-index 10) */
    pointer-events: none;
}

/* Payment stage stacks the till lower (.sm-payment-till z-index 3) and
   layers hand-placed money above it (.sm-till-drop z-index 8), so the
   on-till total sits between the two: readable on the black screen when
   nothing overlaps it, obscured by any change piled on the cashier's
   palm. */
.sm-payment-scene .sm-till-pending {
    z-index: 4;
}

/* Belt: cylinder anchored to the bottom of the stage. Flash reference
   has the belt occupy ~32 % of the (4:3) Flash stage height; rendered into
   a 16:9 stage that's the same proportion (~9em on a 28em-tall stage). */
.sm-conveyor-belt,
.sm-payment-belt {
    position: absolute;
    left: 0;
    right: 0;
    top: 17.15em;
    width: 100%;
    height: 9em;
    object-fit: fill;
    pointer-events: none;
}
.sm-payment-belt { z-index: 0; }

/* Till: The till.svg viewBox is 298×353 (aspect 0.844 = taller than wide),
   but in Flash the till was horizontally scaled to look closer to square.
   1.35× the base 16em × 13em → 21.6em × 17.55em. Shared with the
   payment stage's .sm-payment-till so both screens draw the till at
   identical position/size. */
.sm-conveyor-till,
.sm-payment-till {
    position: absolute;
    left: 28.5em;
    top:  10.6em;
    width: 21.6em;
    height: 17.55em;
    pointer-events: none;
    z-index: 10;
}
.sm-payment-till { z-index: 3; }

/* Items track: sits on the visible top portion of the belt (top = 20em,
   tuned to sit on the belt at its current y=17.15em placement). */
.sm-conveyor {
    position: absolute;
    left: 0;
    right: 0;
    top: 20em;
    height: 3em;
    overflow: visible;
}

/* Next button anchored to the bottom-right, overlapping the till's lower
   edge — mirrors Flash where the pencil tab sits inside the till's base. */
.sm-conveyor-next {
    position: absolute;
    right: 0.5em;
    bottom: 0.5em;
    z-index: 20;
}

/* Reassert `position: absolute` under keyboard focus. The shared
   `.sm-screen .pencil_btn:focus-visible` rule near the top of the file
   sets `position: relative` so its `z-index: 25` takes effect on the
   default-static pencil buttons; this one is anchored bottom-right of
   the scene, so it must stay absolute for the right/bottom offsets
   above to keep resolving against the scene's box. Specificity matches
   the shared rule (both 0,3,0) — later in source wins the tie. */
.sm-conveyor-scene .sm-conveyor-next:focus-visible {
    position: absolute;
}

/* Each conveyor item: actual product sprite sliding LEFT → RIGHT along
   the belt, passing behind the till sprite and continuing off the right
   edge of the screen. Flash frame_06 moves the `newItem*` clips across
   the belt (the orange dots seen in extracted reference captures are a
   runtime fallback when sprites fail to attach; the deployed Flash showed
   actual item graphics).

   Single linear translate keyframe (constant velocity, mirrors Flash
   frame_06's `_x += moveX` per frame with no accel/decel at the till).
   Beep + till tick are scheduled by supermarket-render.js via setTimeout
   at t = 2.4 s per item (item passing the scanner). The last item's
   completeMs timer fires the till-total reveal.

   --sm-conveyor-exit-x     : translateX at the moment the item leaves the
                              stage on the right (off-screen). Chosen so
                              travel is at constant velocity across the
                              whole 4.1 s: the till's scanner window at
                              ~40.95em is crossed at t = 2.4 s (58.5 % of
                              4.1 s), matching the beep setTimeout. */
.sm-conveyor-item {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-direction: column;
    width: 9em;
    height: 9em;
    left: -9em;            /* start just off the left edge so it enters the belt */
    top: 50%;
    /* exit-x: the item travels at constant velocity (17.06 em/s) so the
       till's scanner window at ~40.95em is crossed at t = 2.4 s. Over
       the full 4.1 s that puts the end position at ~70em translate —
       the item's left edge sits at 61em, well off-stage (stage width
       = 50em). Item starts at left:-9em with width 9em (item centre at
       -4.5em when translateX=0); till sits at left:28.5em width:21.6em
       with the scanner window ~30 % from its left edge. */
    --sm-conveyor-exit-x: 70em;
    /* Timing mirrors Flash frame_06.as: items move 5 px/frame at 24 fps
       (= 120 px/s, ≈ 17 em/s here) and are spaced 140 px (~1.17 s) apart
       on the belt. `sayTotal` fires `3100 + N × 1000` ms after the
       conveyor starts. Items start 1.0 s apart; total per-item travel is
       4.1 s, so the last item's exit ends at `(N-1) × 1.0 + 4.1 = N + 3.1`
       s after the conveyor starts. supermarket-render.js schedules the
       beep + till tick at t = 2.4 s per item (item at scanner) via
       setTimeout. */
    animation: sm-conveyor-belt 4.1s linear forwards;
    animation-delay: calc(var(--item-index) * 1s);
    transform: translate(0, -50%);
}

/* Item sprite sized so products at the checkout read at a smaller scale
   than the shelf sprites — they're meant to pass behind the till. */
.sm-conveyor-img {
    display: block;
    width: 5.46em;
    height: 5.04em;
    object-fit: contain;
}

@keyframes sm-conveyor-belt {
    0%   { transform: translate(0,                                -50%); }
    100% { transform: translate(var(--sm-conveyor-exit-x, 70em),  -50%); }
}

/* Till total fade-in once the conveyor finishes. */
.sm-till-total-reveal {
    animation: sm-till-total-fade 0.4s ease-out forwards;
}

@keyframes sm-till-total-fade {
    from { opacity: 0; transform: translateY(0.3em); }
    to   { opacity: 1; transform: translateY(0);     }
}

/* --- Payment screen ---
   Flash frame_07 scene: pale cyan background, customer's hand at top-right
   fanning the bank of money (£5/£10/£20 notes plus 1p..£2 coins), brown
   leather wallet at bottom-left with three note slots held by the cashier's
   hand, black counter band running horizontally across the middle.
*/

/* Payment sub-screen — block shell. */
.sm-screen-layout--payment {
    background: #e0f7f5;
    /* Match .sm-conveyor-screen so the belt+till sit in the same place on
       both stages (conveyor animation and payment). */
    display: block;
    position: relative;
    overflow: hidden;
    padding: 0;
    gap: 0;
}

/* Belt + till on the payment stage share their positioning + sizing with
   the conveyor stage via merged selector rules (see .sm-conveyor-belt,
   .sm-conveyor-till above) so the shopping-counter backdrop is
   pixel-identical across the two screens. Only the z-indexes differ,
   which are overridden in those merged rules. */

/* Payment nav: Done + Next pencils positioned above the till, similar to
   how the conveyor's Next sits inside/near the till. */
.sm-payment-nav {
    position: absolute;
    right:  0.55em;
    bottom: 14.3em;
    display: flex;
    gap: var(--dw-space-loose);
    z-index: 20;
    margin-top: 0;
    padding-top: 0;
}

/* Cashier's spoken line ("That's £X please") shown on the left of the
   payment screen, matching Flash frame_07's cashierText position.
   Sits above the belt/till/wallet in the stacking context. */
.sm-cashier-text {
    position: absolute;
    top: 3em;
    left: 2em;
    max-width: 22em;
    margin: 0;
    font-size: 1.3em;
    color: #205313;
    text-shadow: 0 0.05em 0.15em rgba(255,255,255,0.7);
    z-index: 6;
    pointer-events: none;
}

/* Graphical scene container — fills the entire screen, mirroring the
   conveyor stage so belt/till appear in the same place across both. */
.sm-payment-scene {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

/* Loose coins in the wallet — single overlapping row over the wallet
   body with a per-coin y-jitter so it reads as a scattered handful.
   Each coin has an absolute left keyed to its data-idx so removing
   one (when the user places it on the hand) leaves the slot empty
   rather than the row collapsing to close the gap.  Only coins live
   here; £5/£10/£20 notes are peek buttons inside .sm-wallet-group. */
.sm-cashier-hand-money {
    position: absolute;
    left: 3.697em;
    bottom: 2.218em;
    width: 14em;
    height: 3em;
    pointer-events: auto;
    z-index: 5;
    padding: 0.3em 0.5em;
    box-sizing: border-box;
    transform: translate(1.62em, -1.39em) scale(1.3375);
    transform-origin: top left;
}

.sm-cashier-hand-money .sm-money-coin {
    position: absolute;
    top: 50%;
    transform: translateY(calc(-50% + var(--y-jitter, 0em)));
}

/* Fixed slot per denomination — left in em from walletArea's padding
   edge; y-jitter is a small intrinsic offset that keeps the row from
   looking too grid-like. */
.sm-cashier-hand-money .sm-money-coin[data-idx="0"] { left: 0em;     --y-jitter: -0.2em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="1"] { left: 0.9em;   --y-jitter:  0.3em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="2"] { left: 2.5em;   --y-jitter: -0.4em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="3"] { left: 4.1em;   --y-jitter:  0.1em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="4"] { left: 5.35em;  --y-jitter: -0.3em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="5"] { left: 7.25em;  --y-jitter:  0.4em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="6"] { left: 8.75em;  --y-jitter: -0.1em; }
.sm-cashier-hand-money .sm-money-coin[data-idx="7"] { left: 10.25em; --y-jitter:  0.2em; }

/* Money handed to the cashier — piled on the cashier's palm at the
   top-right (Flash cashierStartLocs).  Sits ABOVE the hand sprite so
   placed money reads as being in front of the palm.  Children are
   absolutely positioned, each offset by their append-order index so
   later placements overlap and slightly cascade off the earlier ones. */
.sm-till-drop {
    position: absolute;
    right: 3.999em;
    top: 4.999em;
    width: 14em;
    height: 8em;
    overflow: visible;
    z-index: 8;                     /* above .sm-cashier-hand-sprite (z 6) */
    pointer-events: auto;
    transform: translate(-3.35em, 0) scale(1.25);
    transform-origin: top right;
}

.sm-till-drop .sm-money-btn {
    position: absolute;
    left: var(--till-left, 0);
    top:  var(--till-top, 0);
    z-index: calc(var(--till-idx, 0) + 1);
}
/* Placed coins always paint above placed notes, regardless of which
   was placed first — coins sit on top of the pile visually. */
.sm-till-drop .sm-money-coin {
    z-index: calc(var(--till-idx, 0) + 100);
}

/* Group-level scan rings on the till-drop and wallet-coins clusters —
   each is a mostly-empty container holding sprites, so the shared
   rectangular box-shadow paints a distracting rectangle over the wallet
   / palm. Drop-shadow chain instead traces each contained sprite's
   silhouette, matching the shelf-item / trolley glow. */
.sm-till-drop.scan_highlight,
.sm-cashier-hand-money.scan_highlight {
    box-shadow: none;
    filter: drop-shadow(0 0 0.25em #ff8800)
            drop-shadow(0 0 0.15em #ff8800)
            drop-shadow(0 0 0.1em  #ff8800);
}
/* Wallet-notes group ring: .sm-wallet-group also holds the wallet body
   sprite and mask overlays, so drop-shadow on the container traces the
   full wallet silhouette instead of the three note strips.  Suppress the
   default group ring and light each peek button individually — three
   glowing strips read as "the notes as a group" without touching the
   wallet body.  Each peek button is overflow:hidden clipped to its
   visible pocket strip (see .sm-wallet-group .sm-wallet-peek-N below),
   so the filter traces the strip rectangle exactly. Mirrors the
   hover/focus treatment further down this file. */
.sm-wallet-group.scan_highlight {
    box-shadow: none;
}
.sm-wallet-group.scan_highlight .sm-wallet-peek.sm-money-btn {
    filter: drop-shadow(0 0 0.25em #ff8800)
            drop-shadow(0 0 0.15em #ff8800)
            drop-shadow(0 0 0.1em  #ff8800);
}

/* --- Wallet at bottom-left, held by the cashier's hand. ---
   Uses Flash sprite_549 (wallet-full.svg) which bundles the cashier hand
   and the brown leather wallet (with three slot dividers) into a single
   SVG.  The cashier hand is at the lower-right of the sprite, the wallet
   body fills most of the upper portion.  Native aspect ratio is 399:465
   ≈ 0.86. */
.sm-wallet-group {
    position: absolute;
    left: -1em;
    bottom: -1em;
    width: 13em;
    height: auto;
    z-index: 2;
    transform: translate(3.45em, 15.35em) scale(1.4);
    transform-origin: top left;
    /* Private stacking context so peek/mask z-indices don't leak into
       the scene-level stack. */
    isolation: isolate;
    /* Shared scale for the three wallet flap masks. */
    --mask-scale: 2.12;
}

.sm-wallet-bg {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 13em;
    height: auto;
    pointer-events: none;
    z-index: 2;
    transform: translate(1.75em, -7.25em);
}

/* Peek notes (each is a real .sm-money-btn — clicking it flies the note
   to the cashier) paired with a wallet-mask overlay (Flash
   walletMask1/2/3).  £5 sits in the FRONT pocket at the top of the
   stack; £20 is at the back:

     wallet-bg      (z 2)   ← backmost
     ├─ £20 note    (z 3)   ─ mask (z 4)
     ├─ £10 note    (z 5)   ─ mask (z 6)
     └─ £5  note    (z 7)   ─ mask (z 8)   ← front pocket / topmost

   Coin row (#smWalletArea) sits above the whole stack when in
   notes+coins mode. */
.sm-wallet-peek,
.sm-wallet-mask {
    position: absolute;
    width: 6em;
    height: auto;
}
.sm-wallet-mask {
    pointer-events: none;   /* masks are decorative overlays */
}
.sm-wallet-peek.sm-money-btn {
    /* Reset the shared .sm-money-btn defaults so the peek button reads
       as a note in a pocket, not an inline flow element. */
    display: block;
    padding: 0;
    background: transparent;
    border: none;
    pointer-events: auto;
}
/* Suppresses a peek note between "user paid with it" and "next round
   renders". Kept in the DOM so its wired-once click handler survives,
   but visually withheld until renderWallet() clears the class. */
.sm-money-await-restore {
    visibility: hidden;
}

.sm-wallet-peek-5  { left: 1.5em;  top: 3.5em;  z-index: 7 !important;
                     transform: translate(0.5em, -21.3em) scale(1.5);
                     transform-origin: top left; }
.sm-wallet-mask-5  { left: 1.5em;  top: 4.5em;  z-index: 8 !important;
                     transform: translate(0.5em, -21em) scale(var(--mask-scale));
                     transform-origin: top left; }
.sm-wallet-peek-10 { left: 3.25em; top: 3em;    z-index: 5 !important;
                     transform: translate(0.25em, -22.3em) scale(1.5);
                     transform-origin: top left; }
.sm-wallet-mask-10 { left: 3.25em; top: 4em;    z-index: 6 !important;
                     transform: translate(-1.4em, -22em) scale(var(--mask-scale));
                     transform-origin: top left; }
.sm-wallet-peek-20 { left: 5em;    top: 2.5em;  z-index: 3 !important;
                     transform: translate(0.5em, -23.2em) scale(1.5);
                     transform-origin: top left; }
.sm-wallet-mask-20 { left: 5em;    top: 3.5em;  z-index: 4 !important;
                     transform: translate(-3.1em, -23em) scale(var(--mask-scale));
                     transform-origin: top left; }

/* --- Money button (used for both hand-fan, counter, and wallet slot). --- */
.sm-money-btn {
    display: inline-block;
    border: none;
    background: transparent;
    padding: 0;
    cursor: pointer;
    /* FLIP-scale animations from onMoneyClick scale the button from
       top-left so the src/dst top-left anchor stays put; the CSS
       class transforms on peek buttons already use this origin. */
    transform-origin: top left;
    /* Coin buttons flow in the flex row inside #smWalletArea; note peek
       buttons pick up their fixed position from .sm-wallet-peek-*. */
}

.sm-money-btn img {
    display: block;
    pointer-events: none;
    object-fit: contain;
}

/* Per-denomination coin sizes — proportional to real-world diameters
   (£2 is 28.4mm; 5p is only 18mm), so a 50p and a 5p aren't the same
   height in the wallet fan. Same ratios as the change cluster, just
   scaled up ~2× for the bank-of-money display. */
.sm-money-coin img {
    width: 3em;
    height: 3em;
}
.sm-money-coin[data-value="1"]   img { width: 2.1em;  height: 2.1em;  }
.sm-money-coin[data-value="2"]   img { width: 2.75em; height: 2.75em; }
.sm-money-coin[data-value="5"]   img { width: 1.9em;  height: 1.9em;  }
.sm-money-coin[data-value="10"]  img { width: 2.6em;  height: 2.6em;  }
.sm-money-coin[data-value="20"]  img { width: 2.25em; height: 2.25em; }
.sm-money-coin[data-value="50"]  img { width: 2.9em;  height: 2.9em;  }
.sm-money-coin[data-value="100"] img { width: 2.5em;  height: 2.5em;  }
.sm-money-coin[data-value="200"] img { width: 3em;    height: 3em;    }

.sm-money-note img {
    width: 10em;
    height: auto;
}

/* Peek-note button image sizing. At rest in the wallet, the image fills
   the 6em peek button.  Placed in the till-drop, it bumps up to the
   note's standard 10em width (same as coins-only fan notes did). */
.sm-wallet-peek.sm-money-btn img {
    width: 6em;
    height: auto;
}
.sm-till-drop .sm-wallet-peek img {
    width: 10em;
    height: auto;
}
/* In the wallet, each peek button's box is clipped to the visible top
   strip that pokes out of its pocket — the rest of the note sits behind
   the corresponding .sm-wallet-mask overlay.  Explicit height + overflow
   (not clip-path) so getBoundingClientRect returns the strip's rect,
   keeping the FLIP src rect and hover glow aligned with what's visible.
   Lifts on reparent into till-drop. */
.sm-wallet-group .sm-wallet-peek-5  { height: 1.6em; overflow: hidden; }
.sm-wallet-group .sm-wallet-peek-10 { height: 1.2em; overflow: hidden; }
.sm-wallet-group .sm-wallet-peek-20 { height: 0.8em; overflow: hidden; }
/* In the till-drop, the resting position + transform from
   `.sm-wallet-peek-N` are neutralised — placement is driven by
   `--till-idx`. Width matches the placed image (10em) so the click
   hit-box tracks the visible sprite. */
.sm-till-drop .sm-wallet-peek {
    transform: none;
    width: 10em;
}

/* Hover/focus feedback traces each coin/note sprite's alpha edge with a
   yellow drop-shadow glow, matching the .sm-change-cluster-btn treatment.
   Yellow (#ffec3b) is deliberately distinct from the orange scan-highlight
   (#ff8800) so mouse users don't confuse hover with switch-scan state.
   Suppress the global button:hover/focus background so the rectangular
   bounding box of the button doesn't paint behind the sprite. */
.sm-money-btn:focus-visible,
.sm-money-btn:focus {
    outline: none;
    background: transparent;
}
@media (hover: hover) {
    .sm-money-btn:hover {
        background: transparent;
    }
}
/* Default: filter on the <img> so the glow hugs the sprite's alpha edge.
   Applies to coins in the wallet fan, to coins in the till-drop, and to
   peek notes once they've been placed into the till-drop (where the
   button's box matches the full note and the alpha trace reads correctly). */
.sm-money-btn:focus-visible img {
    filter: drop-shadow(0 0 0.25em #ffec3b)
            drop-shadow(0 0 0.15em #ffec3b);
}
@media (hover: hover) {
    .sm-money-btn:hover img {
        filter: drop-shadow(0 0 0.25em #ffec3b)
                drop-shadow(0 0 0.15em #ffec3b);
    }
}
/* Wallet peek notes are the exception: the <img> inside each peek button
   is a full-sized note sprite; only a pocket-strip is visible because the
   button has overflow:hidden and a strip height (the rest sits behind the
   .sm-wallet-mask overlays).  The filter goes on the button instead of
   the img so it traces the button's clipped output (the strip rectangle),
   not the full note's alpha.  The <img>-level rule above is nulled here
   so it doesn't compose a second glow. */
.sm-wallet-group .sm-wallet-peek.sm-money-btn:focus-visible img,
.sm-wallet-group .sm-wallet-peek.sm-money-btn:hover img {
    filter: none;
}
.sm-wallet-group .sm-wallet-peek.sm-money-btn:focus-visible {
    filter: drop-shadow(0 0 0.25em #ffec3b)
            drop-shadow(0 0 0.15em #ffec3b);
}
@media (hover: hover) {
    .sm-wallet-group .sm-wallet-peek.sm-money-btn:hover {
        filter: drop-shadow(0 0 0.25em #ffec3b)
                drop-shadow(0 0 0.15em #ffec3b);
    }
}

/* Slimmer scan ring on payable coins/notes. The shared 0.5em ring looks
   fat against small coin sprites in the wallet fan — 0.22em still reads
   as an obvious highlight without visually swallowing the coin. */
.sm-money-btn.scan_highlight {
    --scan-highlight-thickness: 0.22em;
    border-radius: 0.35em;
}

.sm-money-placed {
    /* Visual hint that this item has been paid — slight glow + drop shadow */
    filter: drop-shadow(0 0.1em 0.2em var(--dw-color-shadow-strong));
}

.sm-payment-feedback {
    /* Positioned below the belt (belt bottom ≈ bottom: 2em) so the pill
       sits clear of banknotes travelling from wallet to till. White
       rounded-rect background gives the red text a legible field over
       whichever colour the underlying scene renders. */
    position: absolute;
    left: 50%;
    bottom: 0.5em;
    transform: translateX(-50%);
    text-align: center;
    font-size: 1.3em;
    color: var(--dw-color-feedback-wrong);
    min-height: 1.5em;
    margin: 0;
    padding: 0.15em 0.9em;
    background: #ffffff;
    border-radius: 0.6em;
    box-shadow: 0 0.05em 0.2em rgba(0,0,0,0.2);
    z-index: 4;
    pointer-events: none;
}
/* Collapse the pill's chrome when empty so no white rectangle sits
   under the belt between prompts. */
.sm-payment-feedback:empty {
    background: transparent;
    box-shadow: none;
    padding: 0;
    min-height: 0;
}

/* --- Stage E: post-payment cashier line ("Thanks, here's your change.").
       Visible counterpart of cashierText2 in Flash frame_07 line 1045.
       Sits above the change cluster, fading in as it arrives.

       Split into two classes: `.sm-cashier-text2-slot` carries the
       positioning + typography (always on the element), and
       `.sm-cashier-text2` carries only the fade-in animation. The runtime
       toggles the animation class off and on to re-trigger the keyframe;
       the positioning class stays put so the element never loses its
       layout / colour between fades. */
.sm-cashier-text2-slot {
    position: absolute;
    left: 0;
    right: 0;
    top: 0.4em;
    text-align: center;
    font-size: 1.3em;
    color: #205313;
    min-height: 1.5em;
    margin: 0;
    z-index: 5;
    pointer-events: none;
    text-shadow: 0 0.05em 0.15em rgba(255,255,255,0.7);
}

.sm-cashier-text2 {
    animation: sm-cashier-text-fade 0.4s ease-out;
}

@keyframes sm-cashier-text-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Single cashier-hand sprite used for the whole payment stage. Reaches
   in from the top-right holding an empty palm — resting pose visible
   throughout the coin-payment loop, hidden instantly on Done, then
   slid back in for the change-delivery / see-you-soon beats. */
.sm-cashier-hand-sprite {
    position: absolute;
    width: 12em;
    height: auto;
    /* Position via right/top so the enter/exit keyframes' translate(0,0)
       resting state maps to the visible rest pose.  Rotation must match
       the keyframes' rotate(36deg). */
    right: 5.399em;
    top: -2.5em;
    z-index: 6;
    pointer-events: none;
    transform: rotate(36deg);
    transform-origin: top right;
}

/* Vanish: applied on Done. Instantaneous — the hand withdraws off-stage
   without a tween so the counter reads as "cashier just took the money". */
.sm-cashier-hand-vanish {
    opacity: 0;
    visibility: hidden;
}

/* Slide back in from off the top-right on the change-owed re-entry
   (hand carries the change cluster). The 500ms delay gives a beat
   between "cashier took the money" and "cashier reappears". */
.sm-cashier-hand-enter-change {
    animation: sm-cashier-hand-enter 0.6s ease-out 0.5s both;
}

@keyframes sm-cashier-hand-enter {
    from { transform: translate(20em, -12em) rotate(36deg); opacity: 0; }
    to   { transform: translate(0,    0)     rotate(36deg); opacity: 1; }
}

/* Final exit (after the user takes the change): hand slides off the
   top-right again. */
.sm-cashier-hand-final-exit {
    animation: sm-cashier-hand-exit 0.6s ease-in 0.6s forwards;
}

@keyframes sm-cashier-hand-exit {
    from { transform: translate(0,    0)     rotate(36deg); opacity: 1; }
    to   { transform: translate(20em, -12em) rotate(36deg); opacity: 0; }
}

/* Wallet exit: at "Thanks, see you soon" the customer's hand (wallet
   group) drops away downward alongside the cashier hand's final exit.
   The `from` transforms match the resting transforms on .sm-wallet-group
   and .sm-cashier-hand-money EXACTLY so the wallet doesn't jump to a
   different position for one frame at animation start (which read as
   the wallet lifting up before dropping down). */
.sm-wallet-exit-down {
    /* Delay long enough that the change pile has finished fading into
       the wallet (collect animation runs 1.2s) before the wallet drops
       away — otherwise the wallet slides down under coins that are still
       visible, which reads as the change being spilled. */
    animation: sm-wallet-exit-down 0.6s ease-in 1.2s forwards;
}

@keyframes sm-wallet-exit-down {
    from { transform: translate(3.45em, 15.35em) scale(1.4); opacity: 1; }
    to   { transform: translate(3.45em, 35.35em) scale(1.4); opacity: 0; }
}

.sm-wallet-area-exit-down {
    /* Same delay as .sm-wallet-exit-down — wallet-group + money-fan
       drop together after the change pile has faded. */
    animation: sm-wallet-area-exit-down 0.6s ease-in 1.2s forwards;
}

@keyframes sm-wallet-area-exit-down {
    from { transform: translate(1.62em, -1.39em) scale(1.3375); opacity: 1; }
    to   { transform: translate(1.62em, 22.36em) scale(1.3375); opacity: 0; }
}

/* --- Change cluster (Flash changeClip) ----------------------------------

   A single clickable button — the user "picks up the pile of change" in
   one click (Flash-style, per the stage-E spec).  Greedy-change coins
   are positioned inside the cluster using --sm-cl-x / --sm-cl-y custom
   properties (per-coin) so we don't have to inline pixel positions in JS.

   Resting position roughly matches Flash (570, 160) — over the counter,
   slightly left of centre. Entry tweens from off-top-right (800, -300),
   exit (in stages: to the customer's hand at (235, 439), then off the
   bottom-left to (100, 900)) via the -collect / -exit classes below.
*/
.sm-change-cluster-btn {
    position: absolute;
    border: none;
    background: transparent;
    padding: var(--dw-space-snug);
    cursor: pointer;
    /* Position via right/top so the enter/collect keyframes keep their
       translate(0,0) resting state.  scale stays in transform. */
    right: 3.1em;
    top: 4.749em;
    width: 10em;
    height: 6em;
    z-index: 9;                     /* above hand + till-drop coins */
    transform: scale(2.32);
    transform-origin: top right;
}

/* Hover/focus feedback: only a yellow glow on the individual coin/note
   sprites (via drop-shadow tracing each alpha edge). Suppress the global
   button:hover background (doorway.css) so the invisible bounding rect
   doesn't paint a semi-transparent rounded rectangle behind the pile. */
.sm-change-cluster-btn:focus-visible {
    background: transparent;
}
@media (hover: hover) {
    .sm-change-cluster-btn:hover {
        background: transparent;
    }
}
.sm-change-cluster-btn:focus-visible img {
    filter: drop-shadow(0 0 0.25em #ffec3b)
            drop-shadow(0 0 0.15em #ffec3b);
}
@media (hover: hover) {
    .sm-change-cluster-btn:hover img {
        filter: drop-shadow(0 0 0.25em #ffec3b)
                drop-shadow(0 0 0.15em #ffec3b);
    }
}

/* Scan-highlight: same shape-hugging pattern as hover/focus. The default
   .scan_highlight box-shadow paints a large orange rectangle around the
   invisible 10em × 6em button box, which reads as "the whole quadrant is
   selected" rather than "the pile of coins is selected". Suppress it and
   glow each coin/note sprite via drop-shadow instead. */
.sm-change-cluster-btn.scan_highlight {
    box-shadow: none;
    background: transparent;
}
.sm-change-cluster-btn.scan_highlight img {
    filter: drop-shadow(0 0 0.3em #ff8800)
            drop-shadow(0 0 0.2em #ff8800);
}

/* Coins/notes inside the cluster are decorative — clicks land on the
   parent button as a single target.  Per-denomination widths mirror
   real-world diameters (1p is 20mm; £2 is 28.4mm — noticeably wider;
   £5/£10/£20 notes are ~125/132/139mm — each slightly wider than
   the last).  Notes stay behind, coins scatter on top. */
.sm-change-cluster-btn img {
    position: absolute;
    left: var(--sm-cl-x, 0);
    top:  var(--sm-cl-y, 0);
    pointer-events: none;
    width: 1.6em;                   /* fallback if data-value missing */
    height: auto;
    object-fit: contain;
    z-index: 2;                     /* coins in front of notes */
}

/* Coin sizes — proportional to real-world diameters. Per-value z-index
   is inversely proportional to diameter: smaller coins render on top of
   larger ones so a 5p tucked next to a £2 in the change pile isn't
   swallowed by its neighbour. Notes (data-value >= 500) keep z-index 1
   via the .sm-cl-note rule above; the coin range 3..10 stays above. */
.sm-change-cluster-btn img[data-value="1"]    { width: 1.1em;  z-index: 9; }
.sm-change-cluster-btn img[data-value="2"]    { width: 1.45em; z-index: 5; }
.sm-change-cluster-btn img[data-value="5"]    { width: 1.0em;  z-index: 10; }
.sm-change-cluster-btn img[data-value="10"]   { width: 1.4em;  z-index: 6; }
.sm-change-cluster-btn img[data-value="20"]   { width: 1.2em;  z-index: 8; }
.sm-change-cluster-btn img[data-value="50"]   { width: 1.55em; z-index: 4; }
.sm-change-cluster-btn img[data-value="100"]  { width: 1.3em;  z-index: 7; }
.sm-change-cluster-btn img[data-value="200"]  { width: 1.6em;  z-index: 3; }

/* Note sizes — proportional to real-world widths, sized so notes sit
   alongside the coins in the change cluster without dominating the pile. */
.sm-change-cluster-btn img.sm-cl-note              { z-index: 1; }  /* behind coins */
.sm-change-cluster-btn img[data-value="500"]  { width: 5.32em;  }
.sm-change-cluster-btn img[data-value="1000"] { width: 5.624em; }
.sm-change-cluster-btn img[data-value="2000"] { width: 5.928em; }

/* Entry: cluster slides in from off-right in sync with the cashier
   hand (same 0.5s delay, 0.6s duration, same start offset). */
.sm-change-cluster-enter {
    animation: sm-change-cluster-enter 0.6s ease-out 0.5s both;
}

@keyframes sm-change-cluster-enter {
    from { transform: translate(20em, -12em) scale(2.32); opacity: 0; }
    to   { transform: translate(0,    0)     scale(2.32); opacity: 1; }
}

/* Collect: cluster tweens from rest → over the top of the wallet at
   bottom-left, so the change visibly lands where the customer keeps
   their money. Scale is preserved so the pile doesn't shrink en route.
   Fade-out is folded into the same keyframes (58% → 100%) so the
   arrival and disappearance share one animation. */
.sm-change-cluster-collect {
    animation: sm-change-cluster-collect 1.2s ease-in-out forwards;
}

@keyframes sm-change-cluster-collect {
    0%   { transform: translate(0,      0)     scale(2.32); opacity: 1; }
    58%  { transform: translate(-15em,  8.3em) scale(2.32); opacity: 1; }
    100% { transform: translate(-15em, 10.3em) scale(2.32); opacity: 0; }
}

/* --- Receipt screen ---
   Flash: white paper with horizontal ruled lines, title at the top, table
   filling the body, totals/cash/change at the bottom-right, and a four-
   checkbox self-assessment row below ("How well did you use rounding?").
*/

/* Receipt "ruled paper" geometry.
   --sm-receipt-row is a single em-scaled number that drives both the
   table's line-height AND the striped-paper gradient pitch, so the
   horizontal blue rules always land exactly on each row's baseline
   (rather than drifting between rows). Value = table font-size (1.05em)
   * table line-height (1.6). Bumped once here → everything follows. */
.sm-receipt {
    --sm-receipt-row: 1.68em;
    flex: 1;
    overflow-y: auto;
    padding: 0.8em 1.2em;
    background:
        repeating-linear-gradient(
            to bottom,
            #ffffff 0em,
            #ffffff calc(var(--sm-receipt-row) - 0.05em),
            #b8c8d4 calc(var(--sm-receipt-row) - 0.05em),
            #b8c8d4 var(--sm-receipt-row)
        );
    /* Anchor the gradient so the first blue rule sits on the baseline of
       the "Item / Price / Rounded" header row.
         title font-size 1.4em × margin-bottom 0.6em  ≈ 0.84em
         title padding-bottom 0.2em × 1.4em          ≈ 0.28em
         title height ≈ 1.4em × line-height (~1.15)  ≈ 1.61em
         + container padding-top 0.8em, then one header row-height
         under it. Rather than trying to compute this in CSS, we set
         the position offset to the value that visually lines up
         with the first header baseline (verified in screenshots).
       If the receipt title height or padding changes, re-tune here. */
    background-position: 0 3.35em;
    background-attachment: local;
    border: 1px solid var(--dw-color-border-muted);
    box-shadow: 0 0.2em 0.6em rgba(0,0,0,0.1);
    color: var(--dw-color-text-primary);
}

.sm-receipt-title {
    font-size: var(--dw-font-size-large);
    margin: 0 0 var(--dw-space-comfy) 0;
    text-align: left;
    border-bottom: 1px solid var(--dw-color-border-muted);
    padding-bottom: var(--dw-space-tight);
}

.sm-receipt-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 1.05em;
    /* Row height = --sm-receipt-row (in the receipt container's em),
       which is 1.6em in the table's own em (since font-size is 1.05em).
       Keep them in sync. */
    line-height: 1.6em;
    table-layout: fixed;
}

.sm-receipt-table col.sm-col-item    { width: 50%; }
.sm-receipt-table col.sm-col-price   { width: 25%; }
.sm-receipt-table col.sm-col-rounded { width: 25%; }

.sm-receipt-table th,
.sm-receipt-table td {
    padding: 0 var(--dw-space-comfy);
    border: none;
    text-align: left;
    vertical-align: baseline;
}

.sm-receipt-table thead th {
    font-weight: bold;
    border-bottom: 1px solid var(--dw-color-border-muted);
}

/* Money columns: cells right-aligned (standard money-table
   convention) AND the header sits over the same right edge. */
.sm-receipt-table thead th:nth-child(2),
.sm-receipt-table thead th:nth-child(3),
.sm-receipt-table tbody td:nth-child(2),
.sm-receipt-table tbody td:nth-child(3),
.sm-receipt-table tfoot td {
    text-align: right;
}

.sm-receipt-table tfoot th {
    text-align: right;
    font-weight: bold;
}

.sm-receipt-table tfoot tr:first-child th,
.sm-receipt-table tfoot tr:first-child td {
    border-top: 1px solid var(--dw-color-border-muted);
    padding-top: var(--dw-space-snug);
}

/* Self-assessment row, below the receipt paper. Uses `display: flex` when
   shown, but must respect `.hidden_panel` when round_on=false — the two
   selectors are the same specificity (0,1,0), so a matching-specificity
   compound (`.sm-receipt-eval.hidden_panel`) overrides flex back to none. */
.sm-receipt-eval {
    border: none;
    padding: var(--dw-space-narrow) 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--dw-space-narrow) var(--dw-space-comfy);
    font-size: 1em;
}

.sm-receipt-eval.hidden_panel {
    display: none;
}

.sm-receipt-eval legend {
    font-weight: bold;
    width: 100%;
    margin-bottom: var(--dw-space-tight);
}

/* The rounding-quality answer isn't a real form the app submits — it's
   a self-assessment badge — but keeping it as a radio group means keyboard
   users can still pick one and see the pill highlight the selection.
   Shared pill styling in doorway.css is scoped to `div.user_options`, so
   re-declare the pill look here for the receipt's fieldset. */
.sm-receipt-eval input[type="radio"] {
    /* Hide the native radio dot; the pill label acts as the visual. */
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.sm-receipt-eval label.user_options_radio {
    border: 0.1em solid grey;
    margin: 0.1em;
    padding: 0.1em var(--dw-space-comfy);
    border-radius: 0.5em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}

.sm-receipt-eval input[type="radio"]:checked + label.user_options_radio {
    background-color: chartreuse;
}

/* Same dotted-black focus treatment as the uniform non-money button rule
   near the top of the file; declared separately here because the pill's
   visual is the label adjacent to the (visually hidden) radio input, so
   the selector shape (`input:focus-visible + label`) doesn't slot into
   that comma-list. */
.sm-receipt-eval input[type="radio"]:focus-visible + label.user_options_radio {
    outline: 0.2em dotted black;
    outline-offset: 0.15em;
    position: relative;
    z-index: 25;
}

/* --- Accessibility --- */

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

.sm-print-hint {
    font-size: 0.75em;
    color: var(--dw-color-text-muted);
    text-align: right;
    margin: var(--dw-space-tight) 0 0 0;
}

/* Row that pairs the eval fieldset (left) with the Print button (right),
   between the receipt and the home/Repeat nav row. `align-items: flex-end`
   lands the Print button on the same visual row as the eval pills (the
   fieldset's legend sits above them, so aligning to the bottom keeps
   Print in line with the pill row). When round_on=false the fieldset is
   `display: none` and Print occupies the row alone, still flush right. */
.sm-receipt-eval-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: flex-end;
    gap: var(--dw-space-comfy);
}

.sm-receipt-eval-row > .sm-receipt-eval {
    flex: 1 1 auto;
    margin-right: auto;
}

/* Back pencil pinned to the left of the receipt nav row; Repeat sits
   flush-right thanks to the row's justify-content: flex-end. */
.sm-receipt-back-btn {
    margin-right: auto;
}

/* --- Print stylesheet — show only the receipt paper ---
   The Flash original printed the receipt (frame_08 printButton), so the
   learner can take home a record of their shopping. We strip the page
   chrome, the eval radios, and the action buttons so the printed sheet
   is just the receipt itself. */
@media print {
    @page { margin: 1.5cm; }

    body { background: #fff; }

    #dwNavigationHeader,
    .dw-screen-header,
    .dw-app-footer,
    #dwWelcomeScreen,
    #dwUserOptions,
    #smShoppingScreen,
    #smPaymentScreen,
    .sm-screen-nav,
    .sm-receipt-eval-row,
    .sm-print-hint {
        display: none !important;
    }

    .doorway_application,
    .doorway_fullscreen_div,
    .doorway_aspect_outer_div,
    .doorway_aspect_div,
    main {
        position: static !important;
        width: auto !important;
        height: auto !important;
        max-width: none !important;
        max-height: none !important;
        overflow: visible !important;
        transform: none !important;
        padding: 0 !important;
        margin: 0 !important;
    }

    #smReceiptScreen {
        position: static !important;
        display: block !important;
        width: 100% !important;
        height: auto !important;
        padding: 0 !important;
        overflow: visible !important;
        font-size: 12pt;
    }

    .sm-receipt {
        flex: none;
        overflow: visible;
        box-shadow: none;
        background: #fff;
        border: 1px solid var(--dw-color-border-muted);
    }

    .sm-receipt-table { font-size: 1em; }
}

/* --- Reduced motion ---
   Collapse all animations and transitions to 0.01ms so
   `animationend`/`transitionend` listeners still fire and game-state
   sequencing still works, but the visible motion is removed.

   The conveyor belt is exempt: watching items travel past the scanner
   and the running total tick up is the point of the sub-activity, not
   decoration. Beep + till-total timing (supermarket-render.js) is
   driven by setTimeouts on the same 4.1s schedule as the keyframe, so
   leaving the animation at its natural duration keeps audio and visual
   in step.
*/
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
    .sm-conveyor-item {
        animation-duration: 4.1s !important;
    }
}
