/* ============================================================================
   IMAGE CROP — the frame a visitor drags over a picked image before it uploads.
   ----------------------------------------------------------------------------
   Driven entirely by js/component/image-crop.js, which builds the markup and
   appends it to <body>. Nothing on the site references these classes directly.

   The panel deliberately reuses the site's popup tokens (--popup-* in
   base/root.css) rather than inventing a look: this IS a popup, it just happens
   to be built in JS instead of a Thymeleaf fragment, and a cropper that did not
   look like every other modal would read as a different application.

   base/popup-common.css is NOT imported. The overlay/panel/footer rules there
   are tied to .modal-overlay / .modal markup this component does not use, and
   pulling the sheet in for three tokens would drag the whole popup system (and
   its @imports) onto every page that has an upload field.
   ========================================================================== */

.crop-overlay {
    position: fixed;
    inset: 0;
    /* Above .modal-overlay (100), --front (200) and #nested-popup-container
       (300): the cropper is opened FROM a form inside those, so it has to sit
       on top of whichever one is showing. */
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: var(--popup-scrim, rgba(0, 0, 0, 0.65));
    backdrop-filter: var(--popup-scrim-blur, blur(4px));
    animation: cropOverlayIn 0.2s ease;
}

/* Same motion as every other popup: fade in while moving up. */
@keyframes cropOverlayIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes cropPanelIn {
    from { opacity: 0; transform: translateY(24px); }
    to   { opacity: 1; transform: translateY(0); }
}

.crop-modal {
    background: var(--popup-bg, rgba(80, 50, 130, 0.93));
    backdrop-filter: var(--popup-blur, blur(25px));
    border: var(--popup-border, 2px solid rgba(255, 255, 255, 0.3));
    border-radius: var(--popup-radius, 22px);
    box-shadow: var(--popup-shadow, 0 20px 60px rgba(0, 0, 0, 0.5));
    max-width: 960px;
    width: auto;
    max-height: 94vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: cropPanelIn 0.28s ease;
}

.crop-modal-header {
    padding: 1.4rem 1.6rem 0.9rem;
    text-align: center;
    border-bottom: var(--popup-divider, 1px solid rgba(255, 255, 255, 0.15));
}

.crop-modal-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
    color: #fff;
}

.crop-modal-subtitle {
    margin: 0.35rem 0 0;
    font-size: 0.88rem;
    color: rgba(255, 255, 255, 0.72);
}

.crop-stage-wrap {
    padding: 1.2rem 1.6rem;
    display: flex;
    justify-content: center;
    overflow: auto;
}

/* Sized in JS to the RENDERED image, exactly — so a coordinate inside the
   stage is an image coordinate divided by the current scale, and the frame
   needs no offset maths of its own. */
.crop-stage {
    position: relative;
    overflow: hidden;
    border-radius: 12px;
    /* The checkerboard shows through a transparent PNG, so a visitor can see
       what is actually in the picture rather than guessing against a purple
       panel that happens to match. */
    background-color: rgba(0, 0, 0, 0.35);
    background-image:
        linear-gradient(45deg, rgba(255, 255, 255, 0.06) 25%, transparent 25%),
        linear-gradient(-45deg, rgba(255, 255, 255, 0.06) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.06) 75%),
        linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.06) 75%);
    background-size: 20px 20px;
    background-position: 0 0, 0 10px, 10px -10px, -10px 0;
    /* Without this a drag on a phone scrolls the page instead of moving the
       frame — the pointermove handler never gets past the browser's own pan. */
    touch-action: none;
    user-select: none;
}

.crop-image {
    display: block;
    width: 100%;
    height: 100%;
    /* Deliberately not `contain`: the stage is already the image's exact
       rendered size, so anything but a straight fill would introduce an offset
       between what is drawn and what the crop maths thinks is drawn. */
    object-fit: fill;
    pointer-events: none;
    -webkit-user-drag: none;
}

/* The dark surround is the frame's own outward shadow — one element instead of
   four masking divs, and it can never fall out of step with the frame. */
.crop-frame {
    position: absolute;
    box-sizing: border-box;
    border: 2px solid var(--color-gold, #f5b301);
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.55);
    cursor: move;
    outline: none;
}

.crop-frame:focus-visible {
    border-color: #fff;
}

/* Rule-of-thirds guides: the same reason every camera draws them — they make
   "is the face where I want it" answerable at a glance. */
.crop-frame::before,
.crop-frame::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0.35;
}

.crop-frame::before {
    background-image:
        linear-gradient(to right, transparent calc(33.333% - 1px), #fff calc(33.333% - 1px),
                        #fff 33.333%, transparent 33.333%),
        linear-gradient(to right, transparent calc(66.666% - 1px), #fff calc(66.666% - 1px),
                        #fff 66.666%, transparent 66.666%);
}

.crop-frame::after {
    background-image:
        linear-gradient(to bottom, transparent calc(33.333% - 1px), #fff calc(33.333% - 1px),
                        #fff 33.333%, transparent 33.333%),
        linear-gradient(to bottom, transparent calc(66.666% - 1px), #fff calc(66.666% - 1px),
                        #fff 66.666%, transparent 66.666%);
}

.crop-handle {
    position: absolute;
    width: 18px;
    height: 18px;
    background: var(--color-gold, #f5b301);
    border: 2px solid rgba(0, 0, 0, 0.45);
    border-radius: 4px;
    /* Corners sit half outside the frame so the grab target is not fighting
       the "move the whole frame" area underneath it. */
    z-index: 1;
}

.crop-handle--nw { top: -10px; left: -10px; cursor: nwse-resize; }
.crop-handle--ne { top: -10px; right: -10px; cursor: nesw-resize; }
.crop-handle--se { bottom: -10px; right: -10px; cursor: nwse-resize; }
.crop-handle--sw { bottom: -10px; left: -10px; cursor: nesw-resize; }

.crop-modal-footer {
    display: flex;
    gap: 0.8rem;
    padding: 1rem 1.6rem 1.4rem;
    border-top: var(--popup-divider, 1px solid rgba(255, 255, 255, 0.15));
}

/* Equal-width buttons, capped, exactly like .modal-footer in popup-common.css:
   a lone button stretched across a 900px panel becomes a banner. */
.crop-modal-footer .btn {
    flex: 1;
    max-width: 260px;
    margin: 0 auto;
}

/* Set on <body> while the cropper is open, so the page behind cannot scroll
   out from under it. */
body.crop-open {
    overflow: hidden;
}

/* ── The cropped-result preview the uploader fragment renders ─────────────
   Hidden until image-crop.js has something to put in it. */
.crop-preview {
    margin-top: 0.6rem;
    display: none;
    align-items: center;
    gap: 0.75rem;
}

.crop-preview.is-visible {
    display: flex;
}

.crop-preview img {
    max-width: 200px;
    max-height: 140px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    display: block;
}

.crop-preview-label {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.7);
    font-style: italic;
}

@media (max-width: 640px) {
    .crop-overlay { padding: 0.75rem; }
    .crop-modal { width: 100%; }
    .crop-stage-wrap { padding: 0.9rem; }
    .crop-modal-footer { padding: 0.9rem; }
    .crop-modal-footer .btn { max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
    .crop-overlay,
    .crop-modal { animation: none; }
}
