/* =========================================================
   app.css — additions to your style.css, which is untouched.

   ONE RULE, and it is the one the app kept breaking:
   CSS decides every size. No script measures an element to work
   out how big something should be. Measurement is a race — it
   reads zero while a panel is hidden — which is why the result
   image kept coming out shrunk until it was navigated.

   The image sizes itself from max-width / max-height. Nothing
   can shrink it at the wrong moment because nothing is deciding.
   ========================================================= */

:root {
    /* one height for the artwork, everywhere it appears */
    --hero: clamp(190px, 40vh, 420px);
    --lift: 0 18px 40px -20px rgba(96, 96, 110, 0.6);
    --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
    --unit-wide: 90px;
    --unit-box: 250px;
    --unit-strip: 50px;
    --unit-rail: 160px;
}

/* full-height column, so the footer sits at the bottom of short pages */
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
}

body > footer { margin-top: auto; }
body.noScroll { overflow: hidden; }

/* ---------------- stage and panels ---------------- */

.stage {
    display: grid;
    width: 100%;
    min-width: 0;
    max-width: 320px;
    margin-top: 0;
    margin-inline: auto;
    justify-items: center;
    gap: var(--space-4);
    transition: max-width 0.3s var(--ease);
}

.stage.wide,
.stage.wider { max-width: min(94vw, 720px); }

.cropWorkspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    width: 100%;
    min-width: 0;
}

.cropMain {
    display: grid;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    justify-items: center;
}

/* ---------------- unit slots (collapsed until filled) ----------------
   Insert the unit, then remove [hidden]. :empty slots never take space.
   Class names avoid "ad" so blockers do not hide the frame. */
.unitSlot[hidden],
.unitSlot:empty {
    display: none !important;
}

.unitSlot {
    display: grid;
    place-items: center;
    width: 100%;
    min-width: 0;
    overflow: hidden;
    background: transparent;
}

.unitSlot--wide { min-height: var(--unit-wide); }
.unitSlot--strip { min-height: var(--unit-strip); }
.unitSlot--box {
    width: min(100%, 300px);
    min-height: var(--unit-box);
}

.stage:has(.unitSlot--wide:not([hidden]):not(:empty)),
.stage:has(.unitSlot--strip:not([hidden]):not(:empty)),
.stage:has(.unitSlot--rail:not([hidden]):not(:empty)) {
    max-width: min(96vw, 1080px);
}

@media (min-width: 960px) {
    .stage:has(.unitSlot--rail:not([hidden]):not(:empty)) .cropWorkspace {
        grid-template-columns: 1fr 320px 1fr;
        align-items: start;
        gap: var(--space-5);
        width: 100%;
    }

    .stage:has(.unitSlot--rail:not([hidden]):not(:empty)) .unitSlot--railStart {
        grid-column: 1;
        justify-self: end;
        width: var(--unit-rail);
        min-height: 250px;
    }

    .stage:has(.unitSlot--rail:not([hidden]):not(:empty)) .cropMain {
        grid-column: 2;
        width: 320px;
        justify-self: center;
    }

    .stage:has(.unitSlot--rail:not([hidden]):not(:empty)) .unitSlot--railEnd {
        grid-column: 3;
        justify-self: start;
        width: var(--unit-rail);
        min-height: 250px;
    }
}

@media (max-width: 959px) {
    .unitSlot--rail {
        width: min(100%, 300px);
        min-height: 100px;
    }
}

/* only the active panel exists, so the stage is exactly as tall as it */
.panel { display: none; }

.panel.isOn {
    display: grid;
    animation: panelIn 0.28s var(--ease);
}

.panel.isOn.fromLeft { animation-name: panelInBack; }

@keyframes panelIn {
    from { opacity: 0; transform: translate3d(12px, 0, 0); }
}

@keyframes panelInBack {
    from { opacity: 0; transform: translate3d(-12px, 0, 0); }
}

.result,
.editor {
    max-width: 100%;
    min-width: 0;
    justify-items: center;
    gap: var(--space-4);
    width: 100%;
    margin-top: var(--space-3);
    padding: 0;
    background: none;
    box-shadow: none;
}

body.notOnForm #about {
    opacity: 0;
    max-height: 0;
    margin-top: 0;
    pointer-events: none;
}

header h1,
header p { transition: opacity 0.2s ease; }

header.isSwapping h1,
header.isSwapping p { opacity: 0; }

.passInput[hidden] { display: none; }

/* ---------------- carousel ---------------- */

.resultDeck {
    display: grid;
    max-width: 100%;
    min-width: 0;
    justify-items: center;
    gap: var(--space-3);
    width: 100%;
}

.carousel {
    position: relative;
    width: 100%;
    max-width: 100%;
    /* A grid item's automatic minimum size is its min-content size, and an
       <img> contributes its intrinsic width — `max-width: 100%` does not
       reduce that. So a 1200px card made this column 1200px wide, the page
       wider than the viewport, and everything centred in it sat right of
       where it looked like it should. Every other link in the chain already
       says this; these two were missed. */
    min-width: 0;
    /* NOT clipped. The arrows live here and their shadows would be sliced
       off by an overflow on this element — that was the clipping still
       showing on the buttons. Only the inner window clips. */
    touch-action: pan-y;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.carousel:focus { outline: none; }

.carousel:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: 10px;
}

/* the window the slides move through. Overflow clips at the padding box, so
   the padding is what gives the artwork's shadow room to fall. */
.carouselWindow {
    overflow: hidden;
    width: 100%;
    min-width: 0;
    padding: 0 0 46px;
    box-sizing: border-box;
}

/* one transform, driven by --i. Navigation changes a number, nothing else. */
.carouselTrack {
    display: flex;
    align-items: center;
    transform: translate3d(calc(var(--i, 0) * -100% + var(--drag, 0px)), 0, 0);
    transition: transform 0.36s var(--ease);
}

.carouselTrack.isDragging { transition: none; }

.slide {
    flex: 0 0 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    /* leaves room at the sides for the arrows and the shadow */
    padding: 0 46px;
    box-sizing: border-box;
    opacity: 0.35;
    transform: scale(0.9);
    transition: opacity 0.36s var(--ease), transform 0.36s var(--ease);
}

.slide.isCurrent {
    opacity: 1;
    transform: none;
}

.shot {
    position: relative;
    display: block;
    width: min(100%, calc(var(--hero) * var(--ar, 1.586)));
    max-width: 100%;
    min-width: 0;
    aspect-ratio: var(--ar, 1.586);
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    line-height: 0;
    cursor: pointer;
}

/* Fills the frame above. The frame already has the card's own shape, so
   this cannot clip it or add a margin, and decoding a new file cannot
   change the size. */
.shotImg {
    display: block;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: contain;
    /* square, as it prints */
    border-radius: 0;
    box-shadow: var(--lift);
}



.shotOverlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding: var(--space-5) var(--space-3) var(--space-3);
    border-radius: 4px;
    background: linear-gradient(to top,
            rgba(16, 18, 26, 0.78) 0%,
            rgba(16, 18, 26, 0.52) 30%,
            rgba(16, 18, 26, 0.2) 58%,
            rgba(16, 18, 26, 0.04) 80%,
            rgba(16, 18, 26, 0) 100%);
    opacity: 0;
    transition: opacity 0.28s cubic-bezier(0.33, 0, 0.2, 1);
}

.shotOverlayText {
    font-size: var(--fs-sm);
    line-height: 1.4;
    letter-spacing: 0.3px;
    color: white;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}

.slide.isCurrent .shot:hover .shotOverlay,
.slide.isCurrent .shot:focus-visible .shotOverlay { opacity: 1; }

/* A card being redrawn after an edit: the old picture stays, dimmed, under
   a spinner, so a save never looks like nothing happened. */
.shotBusy {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border-radius: 4px;
    background-color: rgba(250, 248, 244, 0.62);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s var(--ease);
}

.shot.isBusy { cursor: progress; }

.shot.isBusy .shotBusy { opacity: 1; pointer-events: auto; }
.shot.isBusy .shotOverlay { opacity: 0 !important; }

.shotBusySpin {
    width: 26px;
    height: 26px;
    border: 3px solid rgba(33, 83, 204, 0.22);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: rotate 0.75s linear infinite;
}

.shotBusyText {
    font-size: var(--fs-sm);
    line-height: 1.2;
    letter-spacing: 0.2px;
    color: var(--color-text, #2b2b33);
}

/* Save all, while the archive is packed */
#downloadAllButton.isWorking { cursor: progress; }
#downloadAllButton.isWorking svg { display: none; }
#downloadAllButton.isWorking span::before {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: var(--space-2);
    vertical-align: -2px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: rotate 0.7s linear infinite;
}

.carouselBar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
}

/* beside the artwork, vertically centred on it */
.carouselArrow {
    position: absolute;
    top: 50%;
    z-index: 4;
    width: 36px;
    height: 36px;
    margin-top: -18px;
    padding: 0;
    display: grid;
    place-items: center;
    color: var(--color-text-muted);
    background-color: var(--color-surface);
    border-radius: 50%;
    box-shadow: 0 2px 10px -3px rgba(51, 51, 61, 0.35);
    transition: color 0.15s ease, background-color 0.15s ease;
}

.carouselArrow.isPrev { left: 0; }
.carouselArrow.isNext { right: 0; }

.carouselArrow:hover {
    color: white;
    background-color: var(--color-accent);
}

.carouselDots {
    display: flex;
    align-items: center;
    gap: 7px;
}

.carouselDot {
    width: 7px;
    height: 7px;
    padding: 0;
    border-radius: 50%;
    background-color: var(--color-border);
    box-shadow: none;
    transition: background-color 0.18s ease, transform 0.18s ease;
}

.carouselDot:hover { background-color: var(--color-text-muted); }
.carouselDot.isOn { background-color: var(--color-accent); transform: scale(1.3); }

.emptyNote {
    margin: 0;
    padding: var(--space-5) 0;
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

/* ---------------- action row ---------------- */

.actionRow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    max-width: 100%;
    /* buttons cast a shadow on press; without this the panel's own bounds
       cut it off */
    padding: 4px 2px 8px;
}

/* `hidden` has to win. A class setting `display` outbids the browser's own
   `[hidden] { display: none }`, which is why the Print all button stayed on
   screen for a single card however often the code hid it. */
.actionRow button[hidden],
[hidden] { display: none !important; }

/* Update this block in app.css to fix button wrapping */
.actionRow button {
    flex: 1 1 auto; /* Allows buttons to stretch and fill empty space evenly */
    min-width: 110px; /* Prevents them from getting too small */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    font-size: var(--fs-sm);
    line-height: 22px;
    letter-spacing: 0.2px;
}

.actionRow svg {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
}

.buttonGhost {
    color: var(--color-text);
    background-color: var(--color-surface);
    box-shadow: inset 0 0 0 1px var(--color-border-light);
}

.buttonGhost:hover {
    color: var(--color-accent);
    background-color: white;
    box-shadow: inset 0 0 0 1px var(--color-accent);
}

.buttonGhost:disabled {
    color: var(--color-disabled);
    background-color: transparent;
    box-shadow: inset 0 0 0 1px var(--color-border-light);
}

/* navigation is not an achievement, so it carries no fill */
.buttonPlain {
    color: var(--color-text-muted);
    background-color: transparent;
    box-shadow: none;
}

.buttonPlain:hover {
    color: var(--color-accent);
    background-color: transparent;
    box-shadow: none;
}

.buttonPlain:disabled {
    color: var(--color-disabled);
    background-color: transparent;
    box-shadow: none;
}

.btnSpinner {
    display: inline-block;
    width: 13px;
    height: 13px;
    margin-right: var(--space-2);
    vertical-align: -2px;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: white;
    border-radius: 50%;
    animation: rotate 0.7s linear infinite;
}

/* ---------------- editor preview ---------------- */

.editorStage {
    display: grid;
    place-items: center;
    width: 100%;
    max-width: 100%;
    overflow: hidden;
    /* same reason as the carousel: the clip happens at the padding box, so
       this is what lets the shadow show */
    padding: 0px 24px 40px;
    box-sizing: border-box;
}

/* The frame carries the composition's aspect ratio; CSS picks the size, and
   everything inside is a percentage of the frame. Same rule as the carousel:
   no script decides a dimension. */
.cardFrame {
    display: flex;
    align-items: stretch;
    justify-content: center;
    /* --ar is the composition's width/height, handed over as a number. The
       width is whichever is smaller: the room available, or the width this
       shape needs at the hero height. Height then follows from the ratio, so
       the frame can never be taller than --hero nor wider than its parent. */
    width: min(100%, calc(var(--hero) * var(--ar, 1.6)));
    aspect-ratio: var(--ar, 1.6);
    /* the paper the sides are printed on */
    background-color: white;
    border-radius: 4px;
    box-shadow: var(--lift);
}

.cardFrame.isTransparent {
    background-color: transparent;
    background-image:
        linear-gradient(45deg, rgba(51, 51, 61, 0.08) 25%, transparent 25%, transparent 75%, rgba(51, 51, 61, 0.08) 75%),
        linear-gradient(45deg, rgba(51, 51, 61, 0.08) 25%, transparent 25%, transparent 75%, rgba(51, 51, 61, 0.08) 75%);
    background-size: 14px 14px;
    background-position: 0 0, 7px 7px;
}

.cardFrame.isArranging .cardTile:not(.isDragging) { opacity: 0.45; }

.cardTile {
    position: relative;
    overflow: hidden;
    min-width: 0;
    background-color: white;
    cursor: grab;
    touch-action: none;
    transition: opacity 0.18s ease;
}

.cardTile.isDragging {
    cursor: grabbing;
    z-index: 3;
    opacity: 0.96;
}

.cardTileInner {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background-color: white;
}

/* sized by the plan, as a share of the card inside its border */
.cardTileImg {
    display: block;
    flex: none;
    object-fit: fill;
}

.cardTileAction {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding: var(--space-5) var(--space-2) var(--space-2);
    background: linear-gradient(to top,
            rgba(16, 18, 26, 0.8) 0%,
            rgba(16, 18, 26, 0.55) 30%,
            rgba(16, 18, 26, 0.24) 58%,
            rgba(16, 18, 26, 0.06) 80%,
            rgba(16, 18, 26, 0) 100%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.24s cubic-bezier(0.33, 0, 0.2, 1);
}

.cardTileActionText {
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.4px;
    text-align: center;
    text-transform: capitalize;
    color: white;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

.cardTile:hover .cardTileAction { opacity: 1; }

/* ---------------- editor menu ---------------- */

.editorTools {
    display: grid;
    justify-items: center;
    gap: var(--space-2);
    width: 100%;
}

.toolbar {
    display: grid;
    justify-items: center;
    gap: var(--space-3);
    max-width: 100%;
    padding: var(--space-3) var(--space-4);
    border-radius: 14px;
    background-color: var(--color-surface);
    box-shadow: 0 8px 24px -18px var(--shadow-color);
}

.toolbarBody {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: center;
    gap: var(--space-3);
}

/* every control is a labelled column of the same height, so the row shares
   one baseline however many options each control has */
.segment,
.stepper,
.colorField {
    display: grid;
    gap: 5px;
    justify-items: center;
}

.segmentLabel,
.stepLabel {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.stepRow {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 3px;
    border-radius: 999px;
    background-color: var(--color-surface-alt);
}

/* Equal columns, for the same reason .settingsDiv uses them: a sliding
   indicator can only be positioned by CSS if every option is the same
   width. Sized to the widest option, as an intrinsically-sized grid with
   equal flex factors. */
.segmentTrack {
    position: relative;
    display: inline-grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    align-items: center;
    gap: var(--space-1);
    padding: 3px;
    border-radius: 999px;
    background-color: var(--color-surface-alt);
}

/* The indicator. --n (how many options) and --i (which is selected) are
   set by pillPair() in editor.js; nothing is measured. Same contract as
   the carousel's --i in results.js. */
.segmentTrack::before {
    content: "";
    position: absolute;
    top: 3px;
    bottom: 3px;
    left: 3px;
    width: calc((100% - 6px - (var(--n, 2) - 1) * var(--space-1)) / var(--n, 2));
    border-radius: 999px;
    background-color: var(--color-accent);
    transform: translateX(calc(var(--i, 0) * (100% + var(--space-1))));
    transition: transform 0.28s cubic-bezier(0.34, 1.4, 0.64, 1);
    z-index: 0;
}

.segmentOpt {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-width: 52px;
    height: 30px;
    padding: 0 var(--space-3);
    border-radius: 999px;
    font-size: var(--fs-xs);
    letter-spacing: 0.2px;
    text-transform: capitalize;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color 0.15s ease 0.05s;
}

.segmentOpt input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.segmentOpt:hover { color: var(--color-text); }
.segmentOpt svg { display: block; }

/* the script mirrors the checked state as a class, so this works without
   :has() on older Firefox */
/* No background here: the sliding indicator behind the row provides it. */
.segmentOpt.isOn {
    color: white;
}

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

.stepBtn {
    width: 30px;
    height: 30px;
    padding: 0;
    display: grid;
    place-items: center;
    color: var(--color-text);
    background-color: var(--color-surface);
    border-radius: 50%;
    box-shadow: none;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.stepBtn:hover:not(:disabled) {
    color: white;
    background-color: var(--color-accent);
}

.stepBtn:disabled {
    color: var(--color-disabled);
    background-color: transparent;
    cursor: default;
}

.stepWell {
    display: inline-flex;
    align-items: baseline;
    justify-content: center;
    gap: 2px;
    min-width: 56px;
}

.stepValue {
    width: 32px;
    padding: 0;
    border: none;
    background: none;
    outline: none;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    text-align: right;
    color: var(--color-text);
}

.stepValue:focus { color: var(--color-accent); }

.stepUnit {
    font-size: 11px;
    color: var(--color-text-muted);
}

.colorInput {
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: none;
    cursor: pointer;
    box-shadow: inset 0 0 0 1px var(--color-border);
}

.colorInput::-webkit-color-swatch-wrapper { padding: 3px; }
.colorInput::-webkit-color-swatch { border: none; border-radius: 50%; }
.colorInput::-moz-color-swatch { border: none; border-radius: 50%; }

/* A rebuildable group that is not itself a layout box: the width and
   colour controls stay direct flex children of .toolbarBody, so the row's
   baseline alignment is the same as before the wrapper existed. */
.borderControls {
    display: contents;
}

/* the editor's options are written as phrases ("Side by side", "As in PDF") */
.toolbar .segmentOpt { text-transform: none; }

/* the Layout tab in two rows: what size, then where the sides go */
.toolbarBody.isRows { flex-direction: column; align-items: center; gap: 0; }
.toolbarRow {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: center;
    gap: var(--space-3);
}
.toolbarRow + .toolbarRow {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border-light);
    align-self: stretch;
}

.editorHint {
    margin: 0;
    padding: 0;
    font-size: var(--fs-xs);
    line-height: 1.5;
    text-align: center;
    color: var(--color-text-muted);
}

/* =========================================================
   the crop tool
   ========================================================= */

.ck {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: var(--space-4);
    padding: var(--gutter);
    background:
        radial-gradient(120% 80% at 50% 0%, rgba(56, 62, 84, 0.5), transparent 68%),
        rgb(22, 24, 32);   /* opaque: at 0.98 the page's headings ghosted through */
    animation: ckIn 0.16s ease;
}

@keyframes ckIn { from { opacity: 0; } }

.ckHead {
    display: grid;
    justify-items: center;
    gap: 3px;
    text-align: center;
}

.ckTitle {
    margin: 0;
    font-family: "Google Sans", sans-serif;
    font-size: var(--fs-md);
    font-weight: 500;
    letter-spacing: 0.2px;
    color: white;
}

.ckHint {
    margin: 0;
    font-size: var(--fs-xs);
    color: rgba(255, 255, 255, 0.55);
}

/* cards | page | pages */
.ckBody {
    display: grid;
    grid-template-columns: 268px minmax(0, 1fr) auto;
    gap: var(--space-3);
    min-height: 0;
}

/* ---------------- the card panel ---------------- */

.ckPanel {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    gap: var(--space-3);
    min-height: 0;
    padding: var(--space-4) var(--space-3) var(--space-3);
    border-radius: 18px;
    background-color: rgba(255, 255, 255, 0.04);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.ckPanelHead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.ckPanelTitle {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.5);
}

.ckMini {
    height: 27px;
    padding: 0 11px;
    border-radius: 999px;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.9);
    background-color: rgba(255, 255, 255, 0.09);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
    transition: background-color 0.15s ease;
}

.ckMini:hover { background-color: rgba(255, 255, 255, 0.2); }

.ckList {
    display: grid;
    align-content: start;
    gap: var(--space-2);
    min-height: 0;
    overflow-y: auto;
    padding-right: 3px;
    scrollbar-width: thin;
}

.ckList::-webkit-scrollbar { width: 5px; }
.ckList::-webkit-scrollbar-thumb {
    border-radius: 3px;
    background-color: rgba(255, 255, 255, 0.18);
}

.ckCard {
    padding: 10px 11px 11px;
    border-radius: 14px;
    background-color: rgba(255, 255, 255, 0.04);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
    transition: box-shadow 0.16s ease, background-color 0.16s ease;
}

.ckCard:hover { background-color: rgba(255, 255, 255, 0.07); }

.ckCardHead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 9px;
}

.ckCardName {
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: 0.4px;
    color: rgba(255, 255, 255, 0.95);
}

.ckCardMode {
    height: 21px;
    padding: 0 9px;
    border-radius: 999px;
    font-size: 9.5px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
    background-color: rgba(255, 255, 255, 0.08);
    box-shadow: none;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.ckCardMode:hover { color: white; background-color: rgba(255, 255, 255, 0.2); }
.ckCardMode.is-single { color: #14140a; background-color: #f2d544; }

.ckFaces {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.ckCard.is-single .ckFaces { grid-template-columns: 1fr; }

/* one side of one card */
.ckSlot {
    position: relative;
    border-radius: 11px;
    background-color: rgba(0, 0, 0, 0.26);
    box-shadow: inset 0 0 0 1px transparent;
    transition: box-shadow 0.15s ease, background-color 0.15s ease;
}

.ckSlot.is-on { box-shadow: inset 0 0 0 1.5px var(--color-accent); }
.ckSlot.is-dragging { opacity: 0.45; }

.ckSlot.is-over {
    background-color: rgba(33, 83, 204, 0.35);
    box-shadow: inset 0 0 0 2px var(--color-accent);
}

.ckSlot.is-armed {
    background-color: rgba(242, 213, 68, 0.22);
    box-shadow: inset 0 0 0 2px #f2d544;
}

.ckSlot.is-empty { background-color: transparent; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14); }
.ckSlot.is-empty:hover { background-color: rgba(255, 255, 255, 0.06); }

/* removing a side, without going looking for it */
.ckSlotDrop {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 2;
    width: 20px;
    height: 20px;
    padding: 0;
    display: grid;
    place-items: center;
    font-size: 13px;
    line-height: 1;
    color: rgba(255, 255, 255, 0.75);
    background-color: rgba(16, 18, 26, 0.72);
    border-radius: 50%;
    box-shadow: none;
    opacity: 0;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.ckSlot:hover .ckSlotDrop,
.ckSlot.is-on .ckSlotDrop { opacity: 1; }
.ckSlotDrop:hover { color: white; background-color: var(--color-danger); }

/* always reachable without a pointer */
.ckSlotDrop:focus-visible { opacity: 1; outline: 2px solid var(--color-accent); }

.ckShot {
    display: grid;
    gap: 5px;
    width: 100%;
    padding: 6px;
    background: none;
    box-shadow: none;
    border-radius: 11px;
    cursor: pointer;
}

.ckShotMedia {
    display: grid;
    place-items: center;
    height: 66px;
    overflow: hidden;
    border-radius: 7px;
}

.ckSlot:not(.is-empty) .ckShotMedia { background-color: rgba(0, 0, 0, 0.3); }

.ckThumb {
    display: block;
    border-radius: 5px;
}

.ckShotPlus {
    font-size: 17px;
    line-height: 1;
    color: rgba(255, 255, 255, 0.4);
}

.ckShotLabel {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 5px;
    padding: 0 2px;
}

.ckShotFace {
    font-size: 10.5px;
    letter-spacing: 0.4px;
    text-transform: capitalize;
    color: rgba(255, 255, 255, 0.8);
}

.ckSlot.is-on .ckShotFace { color: white; }

.ckShotPage {
    font-size: 9.5px;
    color: rgba(255, 255, 255, 0.4);
}

/* ---------------- the picker ---------------- */

.ckPicker {
    /* fixed, and a child of the overlay: inside the slot it was clipped by
       .ckList's own scrolling and could never open over the page */
    position: fixed;
    z-index: 1200;
    width: 214px;
    max-height: 268px;
    display: grid;
    gap: 6px;
    overflow-y: auto;
    padding: 9px;
    border-radius: 13px;
    background-color: #232734;
    box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.75),
                inset 0 0 0 1px rgba(255, 255, 255, 0.1);
    animation: ckPop 0.14s var(--ease);
}

@keyframes ckPop { from { opacity: 0; transform: translateY(-4px); } }

.ckPickerHead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 10.5px;
    letter-spacing: 0.4px;
    text-transform: capitalize;
    color: rgba(255, 255, 255, 0.6);
}

.ckPickerShut {
    width: 20px;
    height: 20px;
    padding: 0;
    font-size: 13px;
    line-height: 1;
    color: rgba(255, 255, 255, 0.6);
    background: none;
    border-radius: 50%;
    box-shadow: none;
}

.ckPickerShut:hover { color: white; background-color: rgba(255, 255, 255, 0.16); }

.ckPickerDraw {
    padding: 8px 10px;
    border-radius: 9px;
    font-size: 11.5px;
    text-align: left;
    color: #14140a;
    background-color: #f2d544;
    box-shadow: none;
}

.ckPickerDraw:hover { background-color: #ffe45f; }

.ckPickerList { display: grid; gap: 5px; }

.ckPickerItem {
    display: grid;
    grid-template-columns: 62px minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    padding: 5px;
    border-radius: 9px;
    text-align: left;
    background-color: rgba(255, 255, 255, 0.05);
    box-shadow: none;
    cursor: pointer;
}

.ckPickerItem:hover { background-color: rgba(255, 255, 255, 0.16); }

.ckPickerMedia {
    display: grid;
    place-items: center;
    height: 42px;
    overflow: hidden;
    border-radius: 6px;
    background-color: rgba(0, 0, 0, 0.3);
}

.ckPickerMedia .ckThumb { max-width: 100%; height: auto; }

.ckPickerWhere {
    font-size: 11px;
    text-transform: capitalize;
    color: rgba(255, 255, 255, 0.85);
}

.ckPickerNone {
    margin: 0;
    padding: 8px 2px;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.45);
}

.ckPickerDrop {
    padding: 7px;
    border-radius: 9px;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.7);
    background: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}

.ckPickerDrop:hover { color: white; background-color: var(--color-danger); box-shadow: none; }

/* ---------------- the page ---------------- */

.ckStage {
    display: grid;
    min-height: 0;
    min-width: 0;
}

.ckView {
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    background-color: rgba(0, 0, 0, 0.35);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
    touch-action: none;
    cursor: grab;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.ckView:active { cursor: grabbing; }
.ckView.is-armed { cursor: crosshair; }
.ckCanvas { display: block; }

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

.ckMask { fill: rgba(16, 18, 26, 0.62); }

.ckOutline {
    fill: none;
    stroke: rgba(255, 255, 255, 0.7);
    stroke-width: 1.25;
}

.ckShape.is-on .ckOutline {
    stroke: white;
    stroke-width: 1.6;
    stroke-dasharray: 7 5;
    animation: ckAnts 0.9s linear infinite;
}

@keyframes ckAnts { to { stroke-dashoffset: -12; } }

.ckLabel {
    font-family: "Google Sans", sans-serif;
    font-size: 11px;
    letter-spacing: 0.3px;
    text-transform: capitalize;
    fill: rgba(255, 255, 255, 0.75);
    paint-order: stroke;
    stroke: rgba(12, 14, 20, 0.6);
    stroke-width: 3px;
    stroke-linejoin: round;
}

.ckShape.is-on .ckLabel { fill: white; }

.ckHandle {
    position: absolute;
    top: 0;
    left: 0;
    touch-action: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background-color: transparent;
    cursor: nwse-resize;
}
.ckHandle[data-dir="nesw"] { cursor: nesw-resize; }

.ckHandle::after {
    content: "";
    position: absolute;
    inset: 5.5px;
    border-radius: 50%;
    background-color: var(--color-accent);
    box-shadow: 0 0 0 2px white, 0 1px 4px rgba(0, 0, 0, 0.45);
    transition: border-radius 0.15s ease, transform 0.15s ease, background-color 0.15s ease;
}

.ckHandle:hover { background-color: rgba(33, 83, 204, 0.25); }

/* warping: the corners turn into yellow diamonds, matching the Warp switch */
.ck.is-warp .ckHandle,
.ck.is-warp .ckHandle[data-dir] { cursor: move; }
.ck.is-warp .ckHandle:hover { background-color: rgba(242, 213, 68, 0.25); }
.ck.is-warp .ckHandle::after {
    border-radius: 1.5px;
    transform: rotate(45deg) scale(0.9);
    background-color: #f2d544;
}

.ckLoupe {
    position: absolute;
    top: 0;
    left: 0;
    width: 124px;
    height: 124px;
    border: 2px solid white;
    border-radius: 50%;
    box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.7);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
}

.ckLoupe.is-on { opacity: 1; }

.ckBanner {
    position: absolute;
    top: 12px;
    left: 50%;
    z-index: 8;
    display: none;
    align-items: center;
    gap: 10px;
    padding: 7px 8px 7px 13px;
    border-radius: 999px;
    transform: translateX(-50%);
    background-color: #f2d544;
    box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.7);
    white-space: nowrap;
}

.ckBanner.is-on { display: flex; animation: ckBannerIn 0.2s var(--ease); }

@keyframes ckBannerIn { from { opacity: 0; transform: translate(-50%, -8px); } }

.ckBannerDot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #14140a;
    animation: ckPulse 1.1s ease-in-out infinite;
}

@keyframes ckPulse { 50% { opacity: 0.25; } }

.ckBannerText {
    font-size: 12px;
    font-weight: 500;
    text-transform: capitalize;
    color: #14140a;
}

.ckBannerStop {
    height: 25px;
    padding: 0 11px;
    border-radius: 999px;
    font-size: 11px;
    color: #14140a;
    background-color: rgba(20, 20, 10, 0.15);
    box-shadow: none;
}

.ckBannerStop:hover { background-color: rgba(20, 20, 10, 0.28); }

/* ---------------- the page rail ---------------- */

/* Its own panel, matching the card list: without one the thumbnails floated
   on the backdrop and read as part of the page behind the tool. */
.ckRail {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-2);
    border-radius: 18px;
    background-color: rgba(255, 255, 255, 0.045);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
    scrollbar-width: thin;
}

.ckPage {
    position: relative;
    display: block;
    padding: 0;
    border-radius: 6px;
    background: none;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14);
    overflow: hidden;
    opacity: 0.62;
    transition: opacity 0.15s ease, box-shadow 0.15s ease;
}

.ckPage:hover { opacity: 1; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35); }

/* the page you are on is the bright one */
.ckPage.is-on {
    opacity: 1;
    box-shadow: 0 0 0 2px var(--color-accent);
}

/* a page is paper: white, whatever is behind it */
.ckPageThumb {
    display: block;
    background-color: #fff;
}

.ckPageTag {
    position: absolute;
    right: 4px;
    bottom: 4px;
    min-width: 15px;
    padding: 0 3px;
    border-radius: 4px;
    font-size: 9px;
    line-height: 14px;
    text-align: center;
    color: white;
    background-color: rgba(12, 14, 20, 0.72);
}

.ckPageTag.has-mark { background-color: var(--color-accent); }

/* ---------------- footer ---------------- */

.ckFoot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    /* a panel like the card list and the page rail beside it */
    padding: var(--space-2) var(--space-3);
    border-radius: 18px;
    background-color: rgba(255, 255, 255, 0.04);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.ckTools,
.ckActions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* the tools wrap onto a second line on a phone rather than run off it */
.ckTools { flex-wrap: wrap; }

/* Undo / Redo, first in the crop tool's toolbar */
.ckHistory { display: inline-grid; place-items: center; }
.ckHistory svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ckHistory:disabled { color: rgba(255, 255, 255, 0.35); background-color: rgba(255, 255, 255, 0.06); }

.ckTool {
    height: 34px;
    padding: 0 var(--space-4);
    border-radius: 999px;
    font-size: var(--fs-xs);
    color: white;
    background-color: rgba(255, 255, 255, 0.12);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.ckTool:hover { background-color: rgba(255, 255, 255, 0.24); }
.ckTool.is-on { color: #14140a; background-color: #f2d544; box-shadow: none; }

.ckZoom {
    min-width: 38px;
    height: 30px;
    padding: 0 var(--space-2);
    border-radius: 8px;
    font-size: var(--fs-xs);
    color: white;
    background-color: rgba(255, 255, 255, 0.1);
    box-shadow: none;
}

.ckZoom:hover { background-color: rgba(255, 255, 255, 0.22); }

.ckBtn {
    min-width: 104px;
    height: 38px;
    padding: 0 var(--space-4);
    border-radius: 999px;
    font-size: var(--fs-sm);
    color: white;
    background-color: rgba(255, 255, 255, 0.12);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
}

.ckBtn:hover { background-color: rgba(255, 255, 255, 0.22); }

.ckBtn.is-key {
    color: white;
    background-color: var(--color-accent);
    box-shadow: none;
}

.ckBtn.is-key:hover { background-color: var(--color-accent-hover); }

.ckBtn.is-danger {
    color: white;
    background-color: #c63b3b;
    box-shadow: none;
}

.ckBtn.is-danger:hover { background-color: #ad2f2f; }

.ckConfirm {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    animation: ckPop 0.16s ease;
}

.ckConfirmText {
    margin-right: var(--space-2);
    font-size: var(--fs-sm);
    color: rgba(255, 255, 255, 0.86);
}

@media (max-width: 940px) {
    .ckBody { grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: minmax(0, 1fr) auto; }
    .ckPanel { grid-column: 1 / -1; grid-row: 2; max-height: 32vh; }
    .ckStage { grid-column: 1; grid-row: 1; }
    .ckRail { grid-column: 2; grid-row: 1; flex-direction: column; }
    .ckList { grid-auto-flow: row; }
}

/* ---------------- small screens ---------------- */

@media (max-width: 560px) {
    .actionRow {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--space-2);
    }
    
    /* Reorder the buttons visually without changing the HTML */
    .actionRow > button:nth-child(1) { order: 1; } /* Edit */
    .actionRow > button:nth-child(4) { order: 2; } /* Back */
    .actionRow > button:nth-child(2) { order: 3; } /* Print */
    .actionRow > button:nth-child(3) { order: 4; } /* Save */
    .listSection .listToggle { width: 100%; }
    .toolbarBody { gap: var(--space-2); }
    .ck { padding: var(--space-3); }
    .ckLoupe { width: 104px; height: 104px; }
}

@media (prefers-reduced-motion: reduce) {
    .stage,
    #about,
    header h1,
    header p,
    .slide,
    .carouselTrack,
    .cardTile,
    .shotOverlay,
    .segmentTrack::before,
    .cardTileAction { transition-duration: 0.001ms; }

    .panel.isOn { animation: none; }
    .ck { animation: none; }
    .ckOutline, .ckShape.is-on .ckOutline { animation: none; }
    .btnSpinner { animation-duration: 2s; }
}

/* ---------------- focus ---------------- */

/* The base `button` rule in style.css sets `outline: none`, which removed
   the keyboard ring from every button in the app — there was no focus
   indicator anywhere. :focus-visible is drawn only for keyboard and
   assistive input and never for a mouse click, so restoring it here costs
   pointer users nothing.

   .passInput is left out on purpose: it already signals focus with an
   accent underline and a soft ring, and a second outline would double up. */
button:focus-visible,
.button:focus-visible,
.stepValue:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

/* The round steppers signal their state by filling rather than by outline,
   so focus matches hover. Without this, tabbing onto Turn or +/- looked
   like nothing had happened at all. */
.stepBtn:focus-visible:not(:disabled) {
    color: white;
    background-color: var(--color-accent);
}

/* ---------------- scrollbars ---------------- */

/* One treatment everywhere: a thin track that borrows the surface colour and
   a thumb that only asserts itself on hover. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track { background: transparent; }

*::-webkit-scrollbar-thumb {
    border: 3px solid transparent;
    border-radius: 999px;
    background-clip: content-box;
    background-color: var(--color-border);
}

*::-webkit-scrollbar-thumb:hover { background-color: var(--color-text-muted); }
*::-webkit-scrollbar-corner { background: transparent; }

/* on the dark crop tool the same idea, in reverse */
.ck * { scrollbar-color: rgba(255, 255, 255, 0.22) transparent; }
.ck *::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, 0.22); }
.ck *::-webkit-scrollbar-thumb:hover { background-color: rgba(255, 255, 255, 0.4); }

/* The toast positions itself (style.css sets `position: fixed` on `.toast`),
   so this is only a home for it outside #picker — which is display:none on every
   step but the first, taking every toast with it.

   It must NOT be a box of its own and must NOT re-enable pointer events: the
   toast is invisible but present at all times, and a wrapper that accepted
   clicks swallowed every press in that corner of the screen. That is why
   buttons near the bottom of the editor stopped responding. */
.toastContainer {
    display: contents;
}

.toastContainer .toast { z-index: 2000; }

/* clickable only while it is actually on screen */
.toastContainer .toast.showToast { pointer-events: auto; }

@media print {
    .toastContainer { display: none !important; }
    .unitSlot { display: none !important; }
}

/* the two rows of actions on the results step */
.actionRow.is-all {
    margin-top: calc(var(--space-2) * -1);
}

/* ---------------- the print list ---------------- */

/* Every button here starts from nothing: the site's own `button` is a
   filled accent block, which is right for Crop and wrong for an icon. */
.pl button,
.plChip {
    font: inherit;
    transform: none;
}

/* the way in: floats in a corner once there is something in the list */
.plChip {
    position: fixed;
    right: max(16px, env(safe-area-inset-right));
    bottom: max(16px, env(safe-area-inset-bottom));
    z-index: 900;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 10px 10px 10px 16px;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: #fff;
    border-radius: var(--radius-pill);
    background-color: var(--color-accent);
    box-shadow: 0 10px 28px -10px var(--color-accent-shadow), 0 2px 6px -2px rgba(51, 51, 61, 0.3);
}
.plChip:hover { background-color: var(--color-accent-hover); }
.plChip svg { width: 18px; height: 18px; flex: none; }
.plChipCount {
    min-width: 24px;
    height: 24px;
    padding: 0 7px;
    display: inline-grid;
    place-items: center;
    font-size: var(--fs-xs);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
    border-radius: var(--radius-pill);
    background: #fff;
}
.plChip.isBump { animation: plBump 0.45s var(--ease); }
@keyframes plBump {
    0% { transform: scale(1); }
    35% { transform: scale(1.08); }
    100% { transform: scale(1); }
}
.plLocked .plChip { visibility: hidden; }

/* the card on its way to the list */
.plFly {
    position: fixed;
    z-index: 950;
    margin: 0;
    object-fit: contain;
    pointer-events: none;
    border-radius: 6px;
    box-shadow: 0 18px 40px -14px rgba(28, 28, 38, 0.55);
    transform-origin: center;
    will-change: transform, opacity;
}

/* the drawer */
.pl {
    position: fixed;
    inset: 0;
    z-index: 1000;
    pointer-events: none;
}
.plScrim {
    position: absolute;
    inset: 0;
    background: rgba(28, 28, 38, 0.38);
    opacity: 0;
    transition: opacity 0.25s var(--ease);
}
.plPanel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(440px, 100vw);
    display: grid;
    grid-template-rows: auto 1fr auto auto;
    color: var(--color-text);
    background: var(--color-surface);
    border-radius: var(--radius-xl) 0 0 var(--radius-xl);
    box-shadow: -24px 0 60px -30px rgba(28, 28, 38, 0.5);
    transform: translateX(104%);
    /* hidden once it has slid away: its shadow otherwise showed as a strip
       down the right edge of every page */
    visibility: hidden;
    transition: transform 0.3s var(--ease), visibility 0s linear 0.3s;
    outline: none;
}
.pl.isOpen { pointer-events: auto; }
.pl.isOpen .plScrim { opacity: 1; }
.pl.isOpen .plPanel { transform: none; visibility: visible; transition: transform 0.3s var(--ease), visibility 0s; }
.plLocked { overflow: hidden; }

.plHead {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 var(--space-3);
    padding: var(--space-5) var(--space-5) var(--space-4);
    border-bottom: 1px solid var(--color-border-light);
}
.plTitles { flex: 1; min-width: 0; }
.plTitle {
    margin: 0;
    font-size: var(--fs-lg);
    font-weight: 650;
    letter-spacing: -0.01em;
}
.plSub {
    margin: 2px 0 0;
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}
/* where the list lives: its own full-width line under the title row */
.pl .plKeep {
    flex: 1 0 100%;
    margin: 6px 0 0;
    font-size: var(--fs-xs);
    line-height: 1.4;
    color: var(--color-text-muted);
}
.pl .plKeep.isLost { color: var(--color-danger); }

/* a fixed slot: Clear appearing, or its question opening, moves nothing */
.plClear {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 64px;
    min-height: 32px;
    font-size: var(--fs-sm);
}
.plConfirm {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 6px 6px 6px 12px;
    white-space: nowrap;
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: 0 10px 30px -12px rgba(28, 28, 38, 0.35), inset 0 0 0 1px var(--color-border-light);
    animation: plPop 0.16s var(--ease);
}
@keyframes plPop { from { opacity: 0; transform: translateY(-4px); } }
.plAsk { color: var(--color-text-muted); margin-right: 2px; }

.pl .plTextBtn {
    padding: 6px 10px;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-accent);
    background: transparent;
    border-radius: var(--radius-sm);
}
.pl .plTextBtn:hover { background: var(--color-accent-soft); }
.pl .plTextBtn.is-danger { color: var(--color-danger); }
.pl .plTextBtn.is-danger:hover { background: var(--color-danger-soft); }

.pl .plIcon {
    width: 32px;
    height: 32px;
    padding: 0;
    display: inline-grid;
    place-items: center;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: var(--radius-md);
}
.pl .plIcon svg { width: 16px; height: 16px; }
.pl .plIcon:hover:not(:disabled) { color: var(--color-text); background: var(--color-surface-alt); }
.pl .plIcon:disabled { color: var(--color-border-light); background: transparent; cursor: default; }
.pl .plRemove:hover:not(:disabled) { color: var(--color-danger); background: var(--color-danger-soft); }


.plBody {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0 var(--space-3) var(--space-3);
    scrollbar-width: thin;
}
.plItems {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* each file heads its own cards */
.plGroup {
    min-width: 0;
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: var(--space-4) var(--space-2) 6px;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--color-text);
    background: linear-gradient(var(--color-surface) 80%, rgba(255, 255, 255, 0));
}
.plGroup svg { width: 13px; height: 13px; flex: none; color: var(--color-text-muted); }
.plGroupName { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.plGroupCount {
    margin-left: auto;
    flex: none;
    font-weight: 500;
    color: var(--color-text-muted);
}

.plItem {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2);
    border-radius: var(--radius-lg);
    transition: background-color 0.15s var(--ease);
    animation: plIn 0.22s var(--ease);
}
.plItem:hover { background: rgba(51, 51, 61, 0.035); }
/* minmax(0, 1fr): a grid track otherwise grows to its widest content, and
   a long file name in a heading pushed the whole list sideways into a
   scroll instead of being cut short with an ellipsis */
.plItems { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; }
@keyframes plIn {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: none; }
}
.pl .plThumb {
    width: 84px;
    height: 58px;
    display: grid;
    place-items: center;
    padding: 5px;
    cursor: pointer;
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
    box-shadow: inset 0 0 0 1px rgba(51, 51, 61, 0.06);
    transition: box-shadow 0.15s var(--ease), background-color 0.15s var(--ease);
}
.pl .plThumb:hover {
    background: var(--color-accent-soft);
    box-shadow: inset 0 0 0 1.5px var(--color-accent);
}
.pl .plThumb.isLoading {
    background: linear-gradient(90deg, var(--color-surface-alt) 25%, #f6f6f6 50%, var(--color-surface-alt) 75%) 0 0 / 200% 100%;
    animation: plShimmer 1.2s linear infinite;
}
.pl .plThumb.isLoading img { display: none; }
@keyframes plShimmer { to { background-position: -200% 0; } }
.plThumb img {
    max-width: 100%;
    max-height: 100%;
    border-radius: 2px;
    box-shadow: 0 1px 3px rgba(51, 51, 61, 0.25);
}
.plInfo { min-width: 0; display: grid; gap: 5px; }
.plInfo p { margin: 0; }
.pl .plName {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.plMeta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    font-size: 11px;
    color: var(--color-text-muted);
}
.plSize {
    padding: 1px 7px;
    font-variant-numeric: tabular-nums;
    border-radius: var(--radius-pill);
    background: var(--color-surface-alt);
}
.plScaled { color: rgb(166, 102, 0); }
.plSide {
    display: flex;
    align-items: center;
    gap: 4px;
}
.plStepper {
    display: flex;
    align-items: center;
    border-radius: var(--radius-pill);
    box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.pl .plStepper .plIcon { width: 28px; height: 28px; border-radius: var(--radius-pill); }
.plCount {
    min-width: 24px;
    text-align: center;
    font-size: var(--fs-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.plNote {
    margin: var(--space-3) var(--space-1) 0;
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
}

.plEmpty {
    display: grid;
    justify-items: center;
    text-align: center;
    gap: var(--space-2);
    padding: 15% var(--space-4) var(--space-5);
}
.plEmpty h3 { margin: var(--space-2) 0 0; font-size: var(--fs-md); }
.plEmpty p {
    max-width: 30ch;
    margin: 0;
    font-size: var(--fs-sm);
    line-height: 1.5;
    color: var(--color-text-muted);
}
.plEmptyArt {
    width: 120px;
    height: auto;
    margin-bottom: var(--space-1);
}

.plUndo {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin: 0 var(--space-4) var(--space-2);
    padding: 6px 6px 6px 14px;
    font-size: var(--fs-sm);
    color: #fff;
    border-radius: var(--radius-md);
    background: rgb(51, 51, 61);
}
.plUndo.isOn { display: flex; animation: plIn 0.2s var(--ease); }
.plUndo span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl .plUndo .plTextBtn { color: #a9c1ff; }
.pl .plUndo .plTextBtn:hover { background: rgba(255, 255, 255, 0.1); }

.plFoot {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-5) max(var(--space-5), env(safe-area-inset-bottom));
    border-top: 1px solid var(--color-border-light);
}
.plFoot.isOff .plFormat,
.plFoot.isOff .plHint { opacity: 0.5; pointer-events: none; }
.plFormat {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: 3px;
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
}
.plFormatLabel {
    padding: 0 var(--space-2) 0 var(--space-2);
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}
.pl .plSeg {
    flex: 1;
    padding: 7px 8px;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: 6px;
}
.pl .plSeg:hover { color: var(--color-text); background: transparent; }
.pl .plSeg.isOn {
    color: var(--color-text);
    font-weight: 600;
    background: var(--color-surface);
    box-shadow: 0 1px 3px rgba(51, 51, 61, 0.16);
}
.plHint {
    margin: 0 2px;
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
}
.plActions {
    display: grid;
    grid-template-columns: 1fr 1.3fr;
    gap: var(--space-2);
    margin-top: var(--space-1);
}
.plActions button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 10px var(--space-3);
    font-size: var(--fs-sm);
    font-weight: 600;
}
.plActions svg { width: 16px; height: 16px; flex: none; }
.plActions button.isWorking { cursor: progress; opacity: 0.75; }

@media (max-width: 560px) {
    .plPanel {
        top: auto;
        width: 100vw;
        max-height: 88vh;
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;
        transform: translateY(104%);
    }
    /* the picture beside both lines: name and size, then copies and remove */
    .plItem { grid-template-columns: 72px minmax(0, 1fr); row-gap: 6px; }
    .pl .plThumb { grid-row: span 2; align-self: start; }
    .pl .plThumb { width: 72px; height: 50px; }
    .plSide { grid-column: 2; justify-content: space-between; }
}

/* ---------------- the print list section on the results ---------------- */

/* Apart from the card's own actions: a hairline, one button, one line. */
.listSection {
    display: grid;
    justify-items: center;
    gap: var(--space-2);
    width: min(100%, 560px);
    margin-top: var(--space-1);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border-light);
}
/* a secondary action: white, medium weight, so Print and Save stay the
   loudest things on the page; added, light green; added and hovered (or
   focused), it says that a press takes the card out */
.listSection .listToggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-width: 220px;
    padding: var(--space-2) var(--space-5);
    font-size: var(--fs-sm);
    font-weight: 500;
    line-height: 22px;
    color: var(--color-text);
    background-color: var(--color-surface);
    border-radius: var(--radius-pill);
    box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.listSection .listToggle:hover {
    color: var(--color-accent);
    background-color: var(--color-surface);
    box-shadow: inset 0 0 0 1px var(--color-accent);
}
.listSection .listToggle svg { width: 16px; height: 16px; flex: none; }
.listToggle .iconDone,
.listToggle .iconRemove,
.listToggle .lblDo { display: none; }
.listToggle.isOn .iconAdd { display: none; }
.listToggle.isOn .iconDone { display: inline; }
.listSection .listToggle.isOn,
.listSection .listToggle.isOn.isFresh:hover {
    color: var(--color-success-text);
    background-color: var(--color-success-soft);
    box-shadow: inset 0 0 0 1px var(--color-success-ring);
}
.listSection .listToggle.isOn:not(.isFresh):hover,
.listSection .listToggle.isOn:not(.isFresh):focus-visible {
    color: var(--color-danger);
    background-color: var(--color-danger-soft);
    box-shadow: inset 0 0 0 1px var(--color-danger-ring);
}
.listToggle.isOn:not(.isFresh):hover .iconDone,
.listToggle.isOn:not(.isFresh):focus-visible .iconDone,
.listToggle.isOn:not(.isFresh):hover .lblIs,
.listToggle.isOn:not(.isFresh):focus-visible .lblIs { display: none; }
.listToggle.isOn:not(.isFresh):hover .iconRemove,
.listToggle.isOn:not(.isFresh):focus-visible .iconRemove { display: inline; }
.listToggle.isOn:not(.isFresh):hover .lblDo,
.listToggle.isOn:not(.isFresh):focus-visible .lblDo { display: inline; }
.listStatus {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2px 6px;
    min-height: 22px;
    margin: 0;
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
    text-align: center;
}
.listStatus:empty { display: none; }
.listDot { opacity: 0.6; }
.listStatus .listLink {
    padding: 2px 4px;
    font: inherit;
    font-weight: 600;
    color: var(--color-accent);
    background: transparent;
    border-radius: var(--radius-sm);
    transform: none;
}
.listStatus .listLink:hover { background: var(--color-accent-soft); }

/* on the form: the chosen file's cards are already in the list */
.DragDrop .fileNote,
.fileNote {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: var(--space-1) 0 0;
    padding: 4px 12px 4px 8px;
    border-radius: var(--radius-pill) !important;
    font-size: var(--fs-xs) !important;
    font-weight: 500;
    line-height: 1.45;
    color: rgb(18, 128, 60) !important;
    border-radius: var(--radius-md);
    background: var(--color-success-soft);
}

@media print {
    .plChip, .pl { display: none !important; }
}

/* ---------------- printing ---------------- */

#printSheet { display: none; }

@media print {
    @page {
        size: A4 portrait;
        /* CK.SHEET (config.js): 8mm top and bottom, 6mm sides, 2.5mm between
           rows, 3mm between cards in a row: five 54mm rows on one A4, inside
           every common printer's printable area */
        margin: 8mm 6mm;
    }

    body > * { display: none !important; }
    /* rows, centred: two ID cards side by side, a wide pair alone */
    body > #printSheet {
        display: flex !important;
        flex-wrap: wrap;
        justify-content: center;
        align-items: flex-start;
        align-content: flex-start;
        gap: 2.5mm 3mm;
    }

    html,
    body {
        margin: 0 !important;
        padding: 0 !important;
        width: auto !important;
        min-height: 0 !important;
        display: block !important;
        background: #fff !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* the figure carries millimetres; the image fits inside it. Nothing in
       this chain can rescale the card. */
    /* one card and the line above it travel together */
    .printBlock {
        display: block;
        margin: 0;
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .printCard {
        display: block;
        margin: 0 auto;
        padding: 0;
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .printCard img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: contain;
    }

}

.fileNote[hidden] { display: none !important; }
.fileNote::before {
    content: "";
    width: 14px;
    height: 14px;
    flex: none;
    border-radius: 50%;
    background: var(--color-success) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / 9px no-repeat;
}

/* card size fields */
.sizeRow { padding: 3px 4px 3px 12px; gap: 2px; }
.sizeRow .stepWell { min-width: 0; }
.sizeValue { width: 40px; text-align: center; }
.sizeTimes { padding: 0 2px; font-size: var(--fs-sm); color: var(--color-text-muted); }
.toolbar .sizeLock {
    width: 30px;
    height: 30px;
    margin-left: 4px;
    padding: 0;
    display: inline-grid;
    place-items: center;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: 50%;
    transform: none;
}
.toolbar .sizeLock:hover { color: var(--color-accent); background: var(--color-accent-soft); }
.toolbar .sizeLock.isOn { color: #fff; background: var(--color-accent); }


/* ---------------- a card from the print list, opening ---------------- */

.result.isOpening .actionRow,
.result.isOpening .listSection { visibility: hidden; }
.resultOpening {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: var(--space-3);
    min-height: var(--hero);
    width: 100%;
}
.resultOpeningSpin {
    width: 30px;
    height: 30px;
    border: 3px solid var(--color-accent-soft-strong);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: rotate 0.75s linear infinite;
}
.resultOpeningText {
    margin: 0;
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

/* ---------------- "Cropped correctly?" (feedback.js) ---------------- */

/* Two small buttons pinned under the card's bottom-right corner, in the
   room the card already leaves above the print row. Out of the flow, so
   the space between card and print row is exactly what it was. feedback.js
   sets top and right from the shown card. */
.result { position: relative; }
.feedbackSlot {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 2;
}
.feedbackSlot:empty { display: none; }

.fb button,
.fbDialog button {
    font: inherit;
    transform: none;
    box-shadow: none;
}

.fb {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px 2px 2px 12px;
    font-size: var(--fs-xs);
    line-height: 1;
    color: var(--color-text-muted);
    white-space: nowrap;
    animation: fbIn 0.35s var(--ease) both;
}
@keyframes fbIn { from { opacity: 0; } }
.fbQ { margin-right: 2px; }
.fb .fbReport {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 26px;
    padding: 0 10px;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: var(--radius-pill);
    transition: color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.fb .fbReport:hover,
.fb .fbReport:focus-visible { color: var(--color-danger); background: var(--color-danger-soft); }

/* sent: a quiet note in place of the question */
.fb.isSent {
    gap: 5px;
    padding: 4px 10px 4px 8px;
    color: var(--color-success-text);
    font-size: var(--fs-sm);
    font-weight: 600;
    animation: fbIn 0.25s ease;
    transition: opacity 0.3s ease, transform 0.3s ease;
}
.fb.isSent svg { flex: none; }
.fb.isSent.isLeaving { opacity: 0; transform: translateY(-4px); }
@keyframes fbIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* the dialog's "sent": a paper plane leaving, in a soft green ring */
.fbDone {
    position: relative;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    justify-self: center;
    border-radius: 50%;
    color: var(--color-success-text);
    background: var(--color-success-soft);
    box-shadow: inset 0 0 0 1px var(--color-success-ring);
    animation: fbPop 0.35s cubic-bezier(0.34, 1.5, 0.64, 1);
}
.fbDone svg { animation: fbFly 0.7s 0.15s cubic-bezier(0.2, 0.8, 0.3, 1) both; }
@keyframes fbFly {
    0% { transform: translate(-3px, 3px); opacity: 0; }
    100% { transform: none; opacity: 1; }
}
@keyframes fbPop { from { transform: scale(0.3); } to { transform: scale(1); } }
/* ---- the dialog ---- */

.fbDialog {
    position: fixed;
    inset: 0;
    z-index: 1100;
    display: grid;
    place-items: center;
    padding: var(--space-4);
}
.fbScrim {
    position: absolute;
    inset: 0;
    background: rgba(28, 28, 38, 0.38);
    opacity: 0;
    transition: opacity 0.25s var(--ease);
}
.fbPanel {
    position: relative;
    display: grid;
    gap: var(--space-3);
    width: min(100%, 440px);
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding: var(--space-5);
    color: var(--color-text);
    text-align: left;
    border-radius: var(--radius-xl);
    background: var(--color-surface);
    box-shadow: 0 24px 60px -24px rgba(28, 28, 38, 0.45);
    opacity: 0;
    transform: translateY(12px) scale(0.98);
    transition: opacity 0.25s var(--ease), transform 0.3s var(--ease);
    outline: none;
}
.fbDialog.isOpen .fbScrim { opacity: 1; }
.fbDialog.isOpen .fbPanel { opacity: 1; transform: none; }
.fbHead { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.fbTitle { margin: 0; font-size: var(--fs-lg); font-weight: 650; letter-spacing: -0.01em; }
.fbDialog .fbClose {
    flex: none;
    width: 32px;
    height: 32px;
    margin: -4px -6px 0 0;
    padding: 0;
    display: inline-grid;
    place-items: center;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: 50%;
}
.fbDialog .fbClose:hover { color: var(--color-text); background: var(--color-surface-alt); }
.fbLead { margin: 0; font-size: var(--fs-sm); color: var(--color-text-muted); }
.fbChips { display: flex; flex-wrap: wrap; gap: 6px; }
.fbDialog .fbChip {
    padding: 6px 12px;
    font-size: var(--fs-xs);
    color: var(--color-text);
    background: var(--color-surface);
    border-radius: var(--radius-pill);
    box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.fbDialog .fbChip:hover { box-shadow: inset 0 0 0 1px var(--color-accent); background: var(--color-surface); }
.fbDialog .fbChip.isOn {
    color: var(--color-accent);
    font-weight: 600;
    background: var(--color-accent-soft);
    box-shadow: inset 0 0 0 1px var(--color-accent);
}
.fbFix {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    padding: 10px 12px;
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
    border-radius: var(--radius-md);
    background: var(--color-accent-soft);
}
.fbDialog .fbLink {
    padding: 0;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--color-accent);
    background: transparent;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.fbNote {
    margin: 0;
    padding-top: var(--space-3);
    font-size: var(--fs-xs);
    line-height: 1.55;
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border-light);
}
.fbActions { display: flex; justify-content: flex-end; gap: var(--space-2); }
.fbDialog .fbSend,
.fbDialog .fbGhost {
    padding: 9px 18px;
    font-size: var(--fs-sm);
    font-weight: 600;
    border-radius: var(--radius-md);
}
.fbDialog .fbSend { color: #fff; background: var(--color-accent); }
.fbDialog .fbSend:hover:not(:disabled) { background: var(--color-accent-hover); }
.fbDialog .fbSend:disabled { opacity: 0.55; cursor: default; }
.fbDialog .fbSend.isWorking { cursor: progress; }
.fbDialog .fbGhost { color: var(--color-text-muted); background: transparent; }
.fbDialog .fbGhost:hover { color: var(--color-text); background: var(--color-surface-alt); }
.fbStatus { margin: 0; font-size: var(--fs-xs); color: var(--color-danger); }
.fbStatus:empty { display: none; }
.fbPanel.isDone { justify-items: center; text-align: center; padding: var(--space-6) var(--space-5); }

@media (max-width: 560px) {
    .fbDialog { place-items: end stretch; padding: 0; }
    .fbPanel { width: 100%; border-radius: var(--radius-xl) var(--radius-xl) 0 0; padding: var(--space-4); }
}
@media (prefers-reduced-motion: reduce) {
    .fb, .fbDone, .fbDone svg, .fbPanel, .fbScrim { transition: none; animation: none; }
}

/* ---------------- the download, on Crop itself (cropprogress.js) ---------------- */

/* While the card finder downloads (first visit only), Crop fills from the
   left: the part still to come is lightened, the label stays put, and a
   small percentage sits at its end. */
#cropButton { position: relative; overflow: hidden; }
#cropButton > span { position: relative; z-index: 1; }
#cropButton::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 0.3);
    transform-origin: right center;
    transform: scaleX(0);
    transition: transform 0.25s linear, opacity 0.3s var(--ease);
    pointer-events: none;
}
#cropButton.isFetching::before { transform: scaleX(calc(1 - var(--p, 0))); }
#cropButton .cropPct {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    font-size: var(--fs-xs);
    font-variant-numeric: tabular-nums;
    opacity: 0.85;
}
@media (prefers-reduced-motion: reduce) {
    #cropButton::before { transition: none; }
}
