/* Shared editor rules, split from configurator.css (Task 14). Used by
   /customize (via configurator-legacy.css) and the three modern editors:
   photo_templates_editor.html, statement_editor.html, vintage_editor.html. */

/* ============================================================================
   Configurator Grid
   ============================================================================ */

.configurator-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--spacing-2xl);
}

@media (min-width: 768px) {

    .configurator-grid {
        grid-template-columns: 1.5fr 1fr;
        align-items: start;
    }
}

@media (min-width: 1024px) {

    .configurator-grid {
        grid-template-columns: 1.8fr 1fr;
    }
}

@media (min-width: 1280px) {

    .configurator-grid {
        grid-template-columns: 2fr 1fr;
    }
}

/* ============================================================================
   Preview Panel
   ============================================================================ */

.preview-panel {
    position: sticky;
    top: calc(60px + env(safe-area-inset-top, 0px) + var(--spacing-lg));
}

.preview-card {
    background: transparent;
    border-radius: 0;
    box-shadow: none;
    overflow: hidden;
}

.preview-image-container {
    position: relative;
    aspect-ratio: 1;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
}

.preview-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
    transition: opacity var(--transition-base);
}

/* Mobile: enlarge the shirt to fill the preview width ("fit the border"). The
   1024×1024 mockup has ~10% empty margin baked in, so the shirt looks small on
   the narrow layout. Scaling the (square) container's image pushes the sleeves
   out to the edges while keeping the WHOLE shirt visible — collar and hem stay
   in frame. overflow:hidden clips only the empty margin, never the shirt.
   Desktop is left as-is. */
@media (max-width: 767px) {

    .preview-image-container {
        overflow: hidden;
    }

    .preview-image {
        transform: scale(1.25);
        transform-origin: center;
    }
}

/* Mobile spacing: desktop keeps the original. Add breathing room above the
   heading (the fixed mobile-preview-bar no longer reserves flow space), and
   tighten the gap below the heading so the full shirt sits a little higher with
   the empty space falling below it. */
@media (max-width: 767px) {

    .configurator {
        padding-top: var(--spacing-lg);
    }

    .configurator .hero {
        margin-bottom: var(--spacing-md);
    }

    /* No divider lines between the configurator form sections (Text Color,
       Pet Name, Font Style, etc.) — the flex `gap` already spaces them.
       Scoped to the configurator form so other pages keep their dividers. */
    .options-form .form-group + .form-group {
        border-top: none;
        padding-top: 0;
    }
}

.preview-loading {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-md);
    background: rgba(255, 255, 255, 0.9);
    color: var(--color-text-muted);
}

.preview-loading.hidden {
    display: none;
}

.spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

/* ============================================================================
   Options Panel
   ============================================================================ */

.options-panel {
    background: transparent;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
}

.options-form {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xl);
}

/* Form Groups */
.form-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.form-label {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--color-text);
    line-height: 1.4;
}

/* .form-description is the same idea as .form-label-desc: a muted helper line
   under a field label. It had no rule at all until now, so every hint in the
   statement and vintage editors rendered as full-size black body text. Sharing
   one declaration rather than adding a second copy is what stops the two from
   drifting apart again. */
.form-label-desc,
.form-description {
    font-size: 1rem;
    font-weight: 400;
    color: var(--color-text-muted);
}

.form-input {
    padding: var(--spacing-md);
    font-family: inherit;
    font-size: 1rem;
    border: 2px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast);
}

.form-input:focus {
    outline: none;
    border-color: var(--color-primary);
}

/* Color Swatches */
.color-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-sm);
}

/* Tap targets customers hit repeatedly (comparing colours, trying fonts,
   stepping quantities). Without this, two quick taps on iOS are read as
   double-tap-to-zoom and the whole page zooms. Page-level pinch-zoom is
   deliberately left alone so anyone who needs to magnify still can. */
.color-swatch {
    touch-action: manipulation;
}

.color-swatch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-xs);
    padding: var(--spacing-sm);
    background: transparent;
    border: 2px solid transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
}

@media (hover: hover) {

    .color-swatch:hover {
        background: var(--color-bg-alt);
    }
}

.color-swatch:active {
    background: var(--color-bg-alt);
}

.color-swatch.active {
    border-color: var(--color-primary);
}

/* Shirt colour fills for .swatch-inner. Shared by every editor (watercolor,
   photo templates, statement tees, vintage); they used to live only in the
   configurator's own stylesheet, which left the other editors' swatches
   blank. */
.swatch-black { background-color: var(--shirt-black); }
.swatch-white { background-color: var(--shirt-white); }
.swatch-cream { background-color: var(--shirt-cream); }
.swatch-navy { background-color: var(--shirt-navy); }
.swatch-grey { background-color: var(--shirt-grey); }

.swatch-inner {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    box-shadow: var(--shadow-sm);
}

.swatch-label {
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* Out of Stock Swatch */
.color-swatch.out-of-stock {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.color-swatch.out-of-stock .swatch-inner {
    position: relative;
}

.color-swatch.out-of-stock .swatch-inner::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 10%;
    width: 80%;
    height: 2px;
    background: var(--color-text-muted);
    transform: rotate(-45deg);
}

/* Size & Quantity Grid */
.size-quantity-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--spacing-xs);
}

.size-quantity-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-xs) var(--spacing-sm);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
}

.size-quantity-row.has-quantity {
    border-color: var(--color-primary);
    background: var(--color-bg-alt);
}

/* Size not stocked in the selected shirt colour (e.g. XL in white). Set by
   size-stock.js from the server's rule; the row stays visible so the customer
   can see the size exists, but it reads clearly as unavailable and its
   controls are disabled. */
.size-quantity-row.is-unavailable {
    opacity: 0.45;
    background: var(--color-bg-alt);
    border-style: dashed;
    cursor: not-allowed;
}

.size-quantity-row.is-unavailable .size-quantity-label {
    text-decoration: line-through;
}

.size-quantity-row.is-unavailable button,
.size-quantity-row.is-unavailable input {
    pointer-events: none;
}

.size-quantity-row.has-quantity .size-quantity-label {
    font-weight: 700;
}

.size-quantity-label {
    min-width: 48px;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--color-text);
}

/* "+50" next to XL / 2XL. Deliberately quiet: it's disclosure, not a
   promotion. Sits inline with the size so the customer sees the surcharge
   at the moment they pick the size, never as a surprise at checkout. */
.size-upcharge-badge {
    margin-left: 6px;
    padding: 1px 5px;
    border-radius: var(--radius-sm);
    background: var(--color-bg-alt);
    border: 1px solid var(--color-border);
    font-size: 0.6875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-light);
    vertical-align: middle;
    white-space: nowrap;
}

.size-quantity-row.has-quantity .size-upcharge-badge {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* Phone: four sizes as a 2x2 (owner, 2026-09-24), each cell reading
   "XL  [- 0 +]" on one line.

   The history matters, because this is the third arrangement. Side by side
   in a 151px track (a grid column at 393px, iPhone 15) a cell wanted its
   label, an inline "+50" and a ~114px stepper, about 190px, and clipped the
   "+" on XL and 2XL. That was fixed with one column on 2026-09-20 and asked
   back to a 2x2 on 2026-09-24.

   It fits now because only the LABEL has a width. The label reserves 34px so
   that all four steppers come out the same size, and the stepper takes the
   rest of the cell: the +/- buttons keep their 40px coarse-pointer size and
   the number field is what gives. At 393px that leaves the field about 17px,
   tight for two digits and never enough to clip a button. A fixed width on
   the stepper could only ever be right at one screen size, which is what the
   original bug was.

   Overrides the 1fr 1fr that style.css sets at this same breakpoint; this
   sheet loads after it in all four editors. */
@media (max-width: 479px) {

    .size-quantity-grid {
        grid-template-columns: 1fr 1fr;
    }

    .size-quantity-row {
        gap: var(--spacing-xs);
        padding: var(--spacing-xs);
    }

    /* Every label reserves the same box, so every stepper gets the same
       remainder and the four steppers are identical (owner, 2026-09-24).
       Without it the cell with the shortest label, M, hands its stepper ~18px
       that 2XL's does not have, and the row of four reads as four different
       controls. 34px is the widest label this picker can produce: the "+50"
       badge stacked under the letter measures about 32px (a 3 character
       tabular "+50" at 11px, plus 5px of padding and a 1px border each side)
       and "2XL" about 27px. A wider badge, if a future upcharge needs four
       digits, grows its own cell rather than clipping. */
    .size-quantity-label {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
        flex: 0 0 auto;
        min-width: 34px;
        line-height: 1.15;
    }

    .size-upcharge-badge {
        margin-left: 0;
    }

    .size-quantity-row .quantity-stepper {
        flex: 1 1 auto;
        width: auto;
        min-width: 0;
        justify-content: space-between;
    }

    .size-quantity-row .quantity-btn {
        flex: 0 0 auto;
    }

    .size-quantity-row .quantity-input {
        flex: 1 1 auto;
        width: auto;
        min-width: 16px;
    }
}

/* Narrower than about 360px, two 82px button pairs plus two labels stop
   fitting however the number field shrinks, so these phones keep one size
   per row, where the cell is wide enough for all of it. */
@media (max-width: 359px) {

    .size-quantity-grid {
        grid-template-columns: 1fr;
    }
}

.quantity-stepper-sm {
    border-width: 1px;
}

.quantity-stepper-sm .quantity-btn {
    width: 30px;
    height: 30px;
    font-size: 0.875rem;
}

.quantity-stepper-sm .quantity-input {
    width: 32px;
    font-size: 0.875rem;
}

/* Quantity Stepper */
.quantity-stepper {
    display: flex;
    align-items: center;
    border: 2px solid var(--color-border);
    border-radius: var(--radius-md);
    width: fit-content;
}

.quantity-btn {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg);
    border: none;
    cursor: pointer;
    font-size: 1.125rem;
    font-family: inherit;
    color: var(--color-text);
    /* Tapping +/- twice quickly is normal; on iOS it was being read as
       double-tap-to-zoom and blowing up the whole page. Declared here as
       well as in photo_templates.css because /customize doesn't load that
       stylesheet. */
    touch-action: manipulation;
    transition: background var(--transition-fast);
}

.quantity-btn:hover {
    background: var(--color-bg-alt);
}

.quantity-btn:first-child {
    border-right: 1px solid var(--color-border);
    border-radius: var(--radius-md) 0 0 var(--radius-md);
}

.quantity-btn:last-child {
    border-left: 1px solid var(--color-border);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

.quantity-input {
    width: 48px;
    text-align: center;
    border: none;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text);
    background: var(--color-bg);
    -moz-appearance: textfield;
}

.quantity-input::-webkit-outer-spin-button,
.quantity-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

@media (pointer: coarse) {

    .quantity-btn {
        width: 44px;
        height: 44px;
    }

    .quantity-stepper-sm .quantity-btn {
        width: 40px;
        height: 40px;
    }
}

/* Form Actions */
.form-actions {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    padding-top: var(--spacing-md);
    border-top: 1px solid var(--color-border);
}

@media (min-width: 480px) {

    .form-actions {
        flex-direction: row;
    }

    .form-actions .btn {
        flex: 1;
    }
}

@media (pointer: coarse) {

    .color-swatch {
        padding: var(--spacing-md);
    }

    .color-swatches {
        gap: var(--spacing-md);
    }

    .swatch-inner {
        width: 44px;
        height: 44px;
    }

    .size-quantity-row {
        min-height: 44px;
    }

    /* Tap feedback */
    .color-swatch,
.btn,
.btn-link {
        -webkit-tap-highlight-color: transparent;
    }

    .color-swatch:active {
        transform: scale(0.92);
    }

    .btn:active,
.btn-link:active {
        transform: scale(0.97);
    }
}

/* ============================================================================
   Pricing Breakdown box (matches /order, /cart pricing card style)
   ============================================================================ */

.pricing-breakdown {
    background: var(--color-bg-alt);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-lg);
    margin-top: var(--spacing-lg);
    margin-bottom: var(--spacing-lg);
}

.pricing-title {
    font-size: 1rem;
    font-weight: 700;
    margin: 0 0 var(--spacing-md);
    letter-spacing: 0.03em;
}

.pricing-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--spacing-xs) 0;
    font-size: 0.9375rem;
    color: var(--color-text);
}

.pricing-row.pricing-total {
    border-top: 1px solid var(--color-border);
    margin-top: var(--spacing-sm);
    padding-top: var(--spacing-sm);
    font-weight: 700;
    font-size: 1.125rem;
}
