/*
 * Builder shell — the two-screen editor layout.
 *
 * The builder is an application shell, not a scrolling page: the topbar and the
 * step rail are fixed, and one scroller holds both screens (Dizajn, then
 * Detalji). Dizajn is sized to the stage minus a peek strip, so the first
 * Detalji card always shows above the fold as the hint that there is more.
 * A phone has neither the rail nor the peek; its own layout is at the end.
 *
 * Loaded after app.css, which owns the invitation canvas, the background grid,
 * the RSVP rows and the design tokens used throughout.
 */

.builder-page {
    /* Height of the scroller, published by assets/builder-shell.js. */
    --builder-stage-h: 100dvh;
    /* Native width of the stage scrollbar, published by builder-shell.js. */
    --builder-scrollbar-w: 0px;
    /* How much of the first Detalji card shows below Dizajn. */
    --builder-teaser-peek: 4.75rem;
    /* Section padding plus the drag hint under the canvas. */
    --builder-canvas-chrome: 4.4rem;
    --builder-canvas-h: calc(var(--builder-stage-h) - var(--builder-teaser-peek) - var(--builder-canvas-chrome));

    height: 100dvh;
    margin: 0;
    overflow: hidden;
}

.builder-shell {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    max-height: 100dvh;
    overflow: hidden;
    background: linear-gradient(155deg, var(--builder-ambient-top), var(--builder-ambient-bottom));
}

/* ---------------------------------------------------------------- topbar -- */

/*
 * The bar is not a surface of its own: it shares the shell's background and
 * draws no rule beneath itself, so the controls read as sitting on the page
 * rather than on a strip laid over it. Nothing scrolls under it — the scroller
 * below is its own element — so there is nothing for a blur or a divider to
 * separate it from.
 */
.builder-topbar {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.5rem;
    padding: 0.56rem calc(0.75rem + var(--builder-scrollbar-w)) 0.56rem 0.75rem;
    background: transparent;
}

.builder-brand-link {
    display: block;
    flex: 0 0 auto;
    width: 156px;
    height: auto;
    padding: 0.35rem 0.55rem;
    overflow: hidden;
    border: 1px solid var(--app-plate-line);
    border-radius: 12px;
    background: var(--app-plate);
    box-shadow: var(--app-plate-shadow);
    opacity: 0.72;
    text-decoration: none;
    backdrop-filter: blur(10px);
    transition: border-color 160ms ease, box-shadow 160ms ease, opacity 160ms ease;
}

.builder-brand-link img {
    display: block;
    width: 100%;
    height: auto;
    max-width: none;
    object-fit: contain;
}

.builder-brand-link:hover,
.builder-brand-link:focus-visible {
    border-color: rgba(56, 87, 79, 0.22);
    opacity: 1;
    box-shadow: 0 14px 34px rgba(24, 60, 52, 0.12);
}

.builder-brand-link:focus-visible {
    outline: 3px solid rgba(85, 124, 112, 0.22);
    outline-offset: 2px;
}

@media (max-width: 575.98px) {
    .builder-brand-link {
        width: 128px;
        padding: 0.28rem 0.4rem;
        border-radius: 10px;
    }
}

.builder-autosave-status {
    display: inline-flex;
    flex: 0 1 auto;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
    margin-left: auto;
    overflow: hidden;
    color: var(--app-plum);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/*
 * On the logo's plate once there is a state to show, so a dark design cannot
 * swallow it. Empty, it keeps no plate: an empty pill would read as a control.
 */
.builder-autosave-status:not(:empty) {
    padding: 0.35rem 0.625rem;
    border-radius: 999px;
    background: var(--app-plate);
    box-shadow: inset 0 0 0 1px var(--app-plate-line), var(--app-plate-shadow);
}

.builder-topbar .view-mode-toggle {
    flex: 0 0 auto;
}

.builder-topbar-account {
    flex: 0 0 auto;
    align-items: center;
    gap: 0.5rem;
}

/* The phone's back arrow stands in for the logo there; a desktop keeps the logo. */
.builder-back {
    display: none;
}

/* ------------------------------------------------------- body and rail -- */

.builder-body {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    align-items: stretch;
    overflow: hidden;
}

.builder-steps {
    display: flex;
    flex: 0 0 clamp(56px, 15vw, 94px);
    flex-direction: column;
    gap: 0.25rem;
    min-height: 0;
    padding: clamp(0.5rem, 2vw, 0.875rem) 0 0.875rem clamp(0.25rem, 1.2vw, 0.625rem);
    overflow-y: auto;
}

.builder-step {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    gap: 0.3rem;
    padding: 0.75rem 0.375rem;
    border: 1px solid rgba(56, 87, 79, 0.1);
    border-radius: 14px;
    background: rgba(255, 253, 248, 0.9);
    color: var(--app-muted);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    box-shadow: 0 4px 12px rgba(37, 61, 54, 0.06);
    transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}

.builder-step svg {
    width: 22px;
    height: 22px;
}

.builder-step[aria-current="true"] {
    border-color: rgba(79, 116, 105, 0.34);
    background: var(--app-mint);
    color: var(--app-deep);
    box-shadow: 0 8px 18px rgba(79, 116, 105, 0.18);
}

.builder-stage {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
}

.builder-scroll {
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior-y: contain;
}

/*
 * The notices overlay the stage rather than sitting in the flow, so neither
 * screen is resized — and neither scroll position shifted — by one appearing.
 */
.builder-notices {
    position: absolute;
    z-index: 70;
    top: 0.75rem;
    left: 50%;
    width: min(100% - 1.5rem, 520px);
    transform: translateX(-50%);
    pointer-events: none;
}

.builder-notices .alert {
    margin-bottom: 0.75rem;
    box-shadow: var(--app-shadow);
    pointer-events: auto;
}

.builder-notices .alert.d-none {
    display: none !important;
}

/* ------------------------------------------------------------- sections -- */

.builder-section {
    display: flex;
    justify-content: center;
    width: 100%;
    scroll-margin-top: 0;
}

/*
 * A section is focused only by builder-shell.js, when the control that switched
 * screens disappears with the switch. It is not a control, so it draws no ring.
 */
.builder-section:focus {
    outline: none;
}

.builder-section-design {
    /* Exactly the stage less the peek, so the next card is what shows below. */
    min-height: calc(var(--builder-stage-h) - var(--builder-teaser-peek));
    /*
     * Centred, so where the invitation cannot use the whole height — a narrow
     * screen, where the rails take the width the card would need to grow into
     * — the space left over is shared above and below it rather than all
     * falling underneath.
     */
    align-items: center;
    padding: clamp(0.75rem, 2.4vw, 1.375rem) clamp(0.375rem, 1.4vw, 1rem);
}

.builder-section-details {
    padding: clamp(0.625rem, 2vh, 1.125rem) clamp(0.75rem, 2vw, 1rem) clamp(1.5rem, 6vh, 3.5rem);
    border-top: 1px solid rgba(56, 87, 79, 0.14);
}

/* ---------------------------------------------------------- design screen -- */

.builder-design-row {
    --builder-gallery-cols: 1;
    --builder-gallery-thumb: 62px;
    --builder-gallery-width: calc(
        var(--builder-gallery-cols) * var(--builder-gallery-thumb)
        + (var(--builder-gallery-cols) - 1) * 0.5rem + 0.75rem
    );

    display: grid;
    grid-template-columns:
        minmax(var(--builder-gallery-width), 1fr)
        minmax(0, auto)
        minmax(var(--builder-gallery-width), 1fr);
    align-items: flex-start;
    gap: clamp(0.375rem, 1.2vw, 1rem);
    width: 100%;
}

/*
 * builder.php lists the row in reading order — invitation, designs, then the
 * tools — so each child is placed in its column here instead of by source
 * order: the tools on the left, the card in the middle, the designs on the
 * right. The one row has to be named too, or the tools, placed last, would
 * start a second one.
 */
.builder-actions {
    grid-column: 1;
    grid-row: 1;
    align-self: flex-start;
    justify-self: end;
}

.builder-add-rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(0.375rem, 1.4vw, 0.625rem);
    padding-top: 0.375rem;
}

.builder-add-label {
    color: var(--app-muted);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-align: center;
    text-transform: uppercase;
}

.builder-add-button {
    display: grid;
    place-items: center;
    gap: 0.125rem;
    width: clamp(42px, 11vw, 54px);
    height: clamp(46px, 12vw, 58px);
    border: 1px solid rgba(56, 87, 79, 0.18);
    border-radius: 14px;
    background: var(--app-panel);
    color: var(--app-ink);
    font-size: 0.6rem;
    font-weight: 700;
    box-shadow: 0 8px 20px rgba(37, 61, 54, 0.07);
    transition: background-color 140ms ease, border-color 140ms ease;
}

.builder-add-button:hover {
    border-color: var(--app-teal);
    background: var(--app-mint);
}

.builder-add-button svg {
    width: 20px;
    height: 20px;
}

/*
 * Dalje: the phone's way from Dizajn to Detalji, at the end of the Dodaj bar.
 * A desktop switches screens with the step rail and never shows it.
 */
.builder-next-button {
    display: none;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.375rem;
    height: 48px;
    margin-left: auto;
    padding: 0 1rem 0 1.25rem;
    border: 0;
    border-radius: 999px;
    background: var(--app-accent);
    color: #fff;
    font-size: 0.94rem;
    font-weight: 700;
    box-shadow: 0 8px 18px rgba(159, 80, 61, 0.3);
    transition: background-color 140ms ease, box-shadow 140ms ease;
}

.builder-next-button:hover {
    background: #8a4433;
    box-shadow: 0 10px 22px rgba(159, 80, 61, 0.34);
}

.builder-next-button:focus-visible {
    outline: 3px solid rgba(159, 80, 61, 0.24);
    outline-offset: 2px;
}

.builder-next-button svg {
    width: 18px;
    height: 18px;
    stroke-width: 2.2;
}

/* Sits at the stage's edge, where WebKit loses clicks on a button's children. */
.builder-next-button > * {
    pointer-events: none;
}

/*
 * The middle grid track is the centring anchor: the two outer tracks are equal,
 * so different widths on the add rail and the gallery cannot push the actual
 * invitation away from the middle of the stage. Both rails align to the edge of
 * that middle track and therefore remain immediately beside the card.
 *
 * The column is exactly as wide as the invitation. The width is *given* here
 * and the frame inside follows at 100%: deriving it the other way round — a
 * shrink-to-fit column asking the frame how wide it is while the frame asks the
 * column — is circular, and both collapse to zero.
 */
.builder-canvas-col {
    display: flex;
    grid-column: 2;
    grid-row: 1;
    flex: 0 1 auto;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    width: calc(var(--builder-canvas-h) * var(--invitation-aspect, 0.8));
    min-width: 0;
    max-width: 100%;
}

/* The column above already carries the card's width; the frame just fills it. */
.builder-page .canvas-frame {
    position: relative;
    width: 100%;
}

/*
 * On the logo's plate, hugging its text. The plate's padding hangs outside the
 * text by the same negative margin, so the hint wraps where it always did and
 * takes no more height than --builder-canvas-chrome budgets for it.
 */
.builder-canvas-hint {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    max-width: calc(100% + 1.5rem);
    margin: -0.3rem -0.75rem;
    padding: 0.3rem 0.75rem;
    border-radius: 999px;
    background: var(--app-plate);
    box-shadow: inset 0 0 0 1px var(--app-plate-line), var(--app-plate-shadow);
    color: var(--app-plum);
    font-size: 0.76rem;
    font-weight: 600;
    line-height: 1.4;
    text-align: center;
    overflow-wrap: anywhere;
}

.builder-canvas-hint svg {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
}

/* ---------------------------------------------------------------- gallery -- */

/*
 * --builder-gallery-cols is how many thumbnails fit side by side; the media
 * queries near the bottom raise it with the viewport, and the aside's width
 * follows from it so the row never has to guess.
 */
.builder-gallery {
    display: flex;
    grid-column: 3;
    grid-row: 1;
    flex: 0 0 var(--builder-gallery-width);
    width: var(--builder-gallery-width);
    flex-direction: column;
    justify-self: start;
    gap: clamp(0.375rem, 1.4vw, 0.625rem);
    min-height: 0;
    /*
     * As tall as the invitation beside it, and no taller. The height has to be
     * given rather than stretched to: the thumbnails stacked are far taller
     * than the card, so a stretching row would take its height from them and
     * the gallery would run off the screen. builder-shell.js measures the
     * rendered frame; --builder-canvas-h is the budget it was sized from and
     * only stands in until the first measurement lands.
     */
    height: var(--builder-canvas-actual-h, var(--builder-canvas-h));
}

.builder-gallery-cats {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 0.3rem;
}

.builder-gallery-scroller {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 0.5rem;
    min-height: 0;
    padding: 2px 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.builder-gallery-cta {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    gap: 0.19rem;
    padding: clamp(0.5rem, 2vw, 0.625rem) 0.375rem;
    border-radius: 14px;
    background: var(--app-plum);
    color: #fffdf8;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    box-shadow: 0 10px 24px rgba(37, 61, 54, 0.2);
}

.builder-gallery-cta:hover {
    background: var(--app-deep);
    color: #fffdf8;
}

.builder-gallery-cta svg {
    width: 18px;
    height: 18px;
}

/*
 * The category tabs builder.js renders into the aside, drawn like the „Dodaj"
 * buttons across from them — same panel, border, radius and weight — so the two
 * rails read as one set of controls.
 */
.builder-gallery-cats .background-template-tab {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    padding: 0.31rem 0.5rem;
    border: 1px solid rgba(56, 87, 79, 0.18);
    border-radius: 12px;
    background: var(--app-panel);
    color: var(--app-ink);
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    box-shadow: 0 8px 20px rgba(37, 61, 54, 0.07);
    transition: background-color 140ms ease, border-color 140ms ease, color 140ms ease;
}

.builder-gallery-cats .background-template-tab:hover {
    border-color: var(--app-teal);
    background: var(--app-mint);
}

.builder-gallery-cats .background-template-tab.is-active {
    border-color: var(--app-plum);
    background: var(--app-plum);
    color: #fffdf8;
    box-shadow: 0 8px 18px rgba(56, 87, 79, 0.28);
}

.builder-page .builder-gallery-scroller .background-grid {
    display: grid;
    grid-template-columns: repeat(var(--builder-gallery-cols), var(--builder-gallery-thumb));
    justify-content: center;
    gap: 0.5rem;
}

.builder-page .builder-gallery-scroller .background-choice {
    position: relative;
    display: block;
    width: 100%;
    min-height: 0;
    aspect-ratio: 4 / 5;
    margin: 0 auto;
    padding: 0;
    overflow: hidden;
    border: 2px solid rgba(56, 87, 79, 0.14);
    border-radius: 9px;
    background-color: #fff;
    background-position: center;
    background-size: cover;
    box-shadow: 0 3px 9px rgba(37, 61, 54, 0.07);
}

/* A full-width upload keeps the same one-per-row shape as the rest. */
.builder-page .builder-gallery-scroller .background-choice.is-custom-background {
    grid-column: auto;
    min-height: 0;
}

.builder-page .builder-gallery-scroller .background-choice.is-active {
    border-color: var(--app-teal);
    box-shadow: 0 6px 16px rgba(79, 116, 105, 0.3);
}

/* A design this invitation may not move to (builder.js): shown, but muted. */
.builder-page .builder-gallery-scroller .background-choice[aria-disabled="true"] {
    cursor: not-allowed;
    filter: grayscale(0.7);
    opacity: 0.45;
    box-shadow: none;
}

/* Keep the paid state readable even on the 52px mobile thumbnails. */
.builder-page .builder-gallery-scroller .background-tier-badge {
    top: 3px;
    right: auto;
    left: 50%;
    width: auto;
    height: auto;
    max-width: calc(100% - 6px);
    padding: 0.2rem 0.28rem;
    overflow: visible;
    border: 1px solid rgba(56, 87, 79, 0.34);
    background: #fff0dc;
    color: #74420f;
    font-size: 0.5rem;
    letter-spacing: 0.02em;
    box-shadow: 0 2px 6px rgba(38, 35, 54, 0.2);
    text-indent: 0;
    white-space: nowrap;
    transform: translateX(-50%);
}

.builder-page .builder-gallery-scroller .is-tier-free .background-tier-badge {
    display: none;
}

/* -------------------------------------------------- canvas floating tools -- */

/*
 * The selection toolbar belongs to the invitation, so it is placed inside the
 * frame and travels with the card; builder-shell.js parks it above whatever is
 * selected. Undo/redo is not about the selection and used to cover the
 * artwork's own top-right corner, so it lives in the topbar instead.
 */
.builder-page .editor-toolbox {
    position: absolute;
    z-index: 60;
    gap: 0.13rem;
    padding: 0.31rem 0.44rem;
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 8px 20px rgba(38, 35, 54, 0.22);
}

.builder-topbar .editor-history-toolbox {
    position: static;
    flex: 0 0 auto;
    gap: 0.13rem;
    padding: 0.19rem;
    border: 1px solid rgba(56, 87, 79, 0.18);
    border-radius: 11px;
    background: #fff;
    box-shadow: none;
}

.builder-page .editor-selection-toolbox {
    top: var(--builder-toolbar-top, 0);
    right: auto;
    bottom: auto;
    left: 50%;
    max-width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
    transform: translate(-50%, -100%) translateY(-0.7rem) scale(0.96);
    transform-origin: center bottom;
}

.builder-page .editor-selection-toolbox.is-visible {
    transform: translate(-50%, -100%) translateY(-0.7rem) scale(1);
}

.builder-page .editor-toolbox-button {
    width: 2.05rem;
    height: 2.05rem;
    min-height: 2.05rem;
    border-radius: 999px;
    color: var(--app-ink);
}

.builder-page .editor-toolbox-button:hover:not(:disabled) {
    background: #f0efe8;
    transform: none;
}

.builder-page .editor-toolbox-button.is-danger {
    color: var(--app-accent);
}

.builder-page .editor-toolbox-button.is-danger:hover:not(:disabled) {
    background: #f7e7e2;
}

.builder-page .editor-toolbox-button svg {
    width: 1rem;
    height: 1rem;
}

.editor-toolbox-pill {
    width: auto !important;
    gap: 0.3rem;
    padding: 0 0.55rem !important;
    font-size: 0.82rem;
    font-weight: 700;
}

.editor-toolbox-pill-value {
    display: block;
    max-width: 96px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.editor-toolbox-pill svg {
    opacity: 0.6;
}

.editor-toolbox-swatch {
    display: block;
    width: 1.05rem;
    height: 1.05rem;
    border: 1px solid rgba(38, 35, 54, 0.2);
    border-radius: 999px;
    background: currentColor;
}

.editor-toolbox-button[aria-expanded="true"] {
    background: var(--app-mint);
}

/*
 * Sibling of the toolbar, not a child: the toolbar scrolls sideways when it is
 * wider than the invitation, and a panel inside it would scroll away with the
 * buttons. It opens just under the toolbar, over the card, as the redesign has
 * it — --builder-toolbar-top is the selection's own top edge.
 */
.editor-popover-layer {
    position: absolute;
    z-index: 61;
    top: calc(var(--builder-toolbar-top, 0px) + 0.6rem);
    left: 50%;
    transform: translateX(-50%);
}

.editor-popover-layer[hidden] {
    display: none;
}

.editor-popover {
    width: 268px;
    max-width: min(78vw, 320px);
    padding: 0.75rem;
    border: 1px solid rgba(56, 87, 79, 0.14);
    border-radius: 14px;
    background: #fff;
    white-space: normal;
    box-shadow: 0 18px 44px rgba(37, 61, 54, 0.22);
}

.editor-popover[hidden] {
    display: none;
}

#textInput[hidden], #textDateControl[hidden] {
    display: none;
}

#textLocationSuggestions {
    position: static;
    max-height: min(250px, 35dvh);
    overflow-y: auto;
    margin-top: 8px;
}

#textLocationStatus:empty {
    display: none;
}

.editor-popover-label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--app-muted);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.editor-popover .form-text {
    margin-top: 0.375rem;
    font-size: 0.75rem;
}

/* ---------------------------------------------------------- details screen -- */

.builder-details {
    display: flex;
    flex-direction: column;
    gap: 1.125rem;
    width: 100%;
    max-width: 660px;
}

/*
 * Collapsed while Dizajn is the active step, so the strip that peeks below the
 * invitation is the first card rather than this title. builder-shell.js
 * expands it before it scrolls Detalji into place.
 */
.builder-details-head {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    overflow: hidden;
    cursor: pointer;
    transition: max-height 240ms ease, opacity 200ms ease, margin-bottom 240ms ease;
}

.builder-page[data-builder-step="dizajn"] .builder-details-head {
    max-height: 0;
    margin-bottom: -1.125rem;
    opacity: 0;
    pointer-events: none;
}

.builder-page[data-builder-step="detalji"] .builder-details-head {
    max-height: 9rem;
    opacity: 1;
}

.builder-details-thumb {
    position: relative;
    flex: 0 0 auto;
    width: 96px;
    aspect-ratio: var(--invitation-aspect, 0.8);
    padding: 0;
    overflow: hidden;
    border: 1px solid rgba(56, 87, 79, 0.16);
    border-radius: 6px;
    background-color: #fff;
    box-shadow: 0 10px 26px rgba(37, 61, 54, 0.12);
}

/*
 * A scaled copy of the live canvas. The renderer sizes text in pixels from the
 * canvas width, so the copy is laid out at the real width and scaled down
 * whole — see syncThumb() in builder-shell.js.
 */
.builder-details-thumb-stage {
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    transform-origin: top left;
    pointer-events: none;
}

/* The title stands on the logo's plate, so a dark design's tint cannot swallow it. */
.builder-details-head-text {
    min-width: 0;
    padding: 0.625rem 0.875rem;
    border-radius: 12px;
    background: var(--app-plate);
    box-shadow: inset 0 0 0 1px var(--app-plate-line), var(--app-plate-shadow);
}

.builder-details-head-text h1 {
    margin: 0 0 0.25rem;
    font-family: "DM Serif Display", Georgia, serif;
    font-size: 1.5rem;
    font-weight: 400;
    line-height: 1.15;
}

.builder-details-head-text p {
    margin: 0;
    color: var(--app-plum);
    font-size: 0.88rem;
    line-height: 1.5;
}

.builder-card {
    padding: 1rem 1.125rem;
    border: 1px solid rgba(56, 87, 79, 0.12);
    border-radius: 16px;
    background: rgba(255, 254, 250, 0.94);
    box-shadow: var(--app-shadow);
}

.builder-card-head {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin-bottom: 0.75rem;
}

.builder-card-head svg {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    color: var(--app-teal);
}

.builder-card-head h2 {
    flex: 1 1 auto;
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}

.builder-card-label {
    display: block;
    margin-bottom: 0.375rem;
    font-size: 0.85rem;
    font-weight: 600;
}

.builder-card-help {
    margin: 0.375rem 0 0;
    color: var(--app-muted);
    font-size: 0.78rem;
}

.builder-card-switch {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(56, 87, 79, 0.1);
}

.builder-card-switch-label {
    flex: 1 1 auto;
    font-size: 0.9rem;
    font-weight: 600;
}

.builder-card-switch-note {
    color: var(--app-muted);
    font-weight: 500;
}

.builder-publish-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    min-height: 48px;
    padding: 0.81rem 1.125rem;
    border: 1px solid var(--app-accent);
    border-radius: 12px;
    background: var(--app-accent);
    color: #fff;
    font-size: 0.95rem;
    font-weight: 700;
    box-shadow: 0 10px 22px rgba(159, 80, 61, 0.22);
    transition: background-color 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
}

.builder-publish-button:hover:not(:disabled) {
    border-color: #8a4433;
    background: #8a4433;
    color: #fff;
    box-shadow: 0 12px 26px rgba(159, 80, 61, 0.3);
}

.builder-publish-button:disabled {
    cursor: wait;
    opacity: 0.65;
}

.builder-publish-button svg {
    width: 18px;
    height: 18px;
}

/*
 * Keep the button itself as the pointer target. WebKit can omit the synthetic
 * click when a label or icon inside a button sits at the edge of this scroller,
 * even though it delivered the complete pointer and mouse sequence to it.
 */
.builder-publish-button > * {
    pointer-events: none;
}

/* The switches in the cards, drawn as the redesign draws them. */
.builder-page .form-switch .form-check-input {
    width: 44px;
    height: 26px;
    margin: 0;
    border-color: rgba(56, 87, 79, 0.24);
    background-color: #eceae2;
    box-shadow: none;
}

.builder-page .form-switch .form-check-input:checked {
    border-color: var(--app-accent);
    background-color: var(--app-accent);
}

.builder-page .form-check.form-switch {
    display: flex;
    flex: 0 0 auto;
    min-height: 0;
    padding-left: 0;
    align-items: center;
}

/* ----------------------------------------------------------- teaser strip -- */

/*
 * The hit area over the peeking card. It is invisible on purpose: what should
 * read as "there is more below" is the card itself, not chrome on top of it.
 */
.builder-teaser-hit {
    position: absolute;
    z-index: 40;
    right: 0;
    bottom: 0;
    left: 0;
    height: var(--builder-teaser-peek);
    padding: 0;
    border: 0;
    background: transparent;
}

.builder-page[data-builder-step="detalji"] .builder-teaser-hit {
    display: none;
}

/* ---------------------------------------------------------------- phones -- */

/*
 * The gallery widens into columns as the screen allows, and folds back to a
 * strip under the invitation on a phone (below). On desktop that computed
 * gallery width is also the minimum for both outer grid tracks: the canvas
 * stays centred, and on a tight screen its middle track gives up width before
 * either side control is clipped.
 */
@media (min-width: 1100px) {
    .builder-design-row {
        --builder-gallery-cols: 2;
    }
}

/*
 * Three columns is the width at which the categories stop being a stack. From
 * here up they lie in two tracks that fill the aside, so a row of them is
 * exactly as wide as the thumbnails below it — the same two-by-two placement at
 * three columns and at four, only wider as the aside widens. Below this the
 * aside is too narrow for two side by side: every label would break over two
 * lines, so they stay one above the other.
 */
@media (min-width: 1360px) {
    .builder-design-row {
        --builder-gallery-cols: 3;
    }

    .builder-gallery-cats {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
    }

    .builder-gallery-cats .background-template-tab {
        min-height: 29px;
        padding: 0.25rem 0.5rem;
        border-radius: 10px;
    }

    /*
     * The catalogue is data, so the count can be odd — a custom-design row is
     * prepended when the account has one. An odd last button takes the whole
     * row rather than sitting half-width with a gap beside it.
     */
    .builder-gallery-cats .background-template-tab:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

@media (min-width: 1600px) {
    .builder-design-row {
        --builder-gallery-cols: 4;
    }
}

/*
 * Phones — variant C of the "Mobile Builder Redesign" canvas.
 *
 * Top to bottom: the topbar with a back arrow in the logo's place, the
 * invitation as wide as the screen allows, the designs, then one bar holding
 * the Dodaj tools and Dalje. There is no step rail and no Detalji peek: Dalje
 * and the back arrow switch the two screens, so Dizajn is exactly the stage
 * tall and does not scroll.
 */
@media (max-width: 767.98px) {
    .builder-page {
        --builder-teaser-peek: 0px;
    }

    /* ---------------------------------------------------------- topbar -- */

    .builder-topbar {
        min-height: 52px;
        gap: 0.25rem;
        padding: 0 0.5rem;
    }

    .builder-brand-link,
    .builder-topbar-account {
        display: none;
    }

    /* On the logo's plate, like the toggle at the other end, so a dark design
       cannot swallow the arrow. Unblurred: nothing passes under the topbar. */
    .builder-back {
        display: inline-flex;
        flex: 0 0 auto;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        padding: 0;
        border: 0;
        border-radius: 12px;
        background: var(--app-plate);
        box-shadow: inset 0 0 0 1px var(--app-plate-line), var(--app-plate-shadow);
        color: var(--app-ink);
        text-decoration: none;
    }

    .builder-back svg {
        width: 26px;
        height: 26px;
        stroke-width: 2.2;
    }

    .builder-back:focus-visible {
        outline: 3px solid rgba(85, 124, 112, 0.22);
        outline-offset: 2px;
    }

    .builder-page[data-builder-step="dizajn"] .builder-back-step,
    .builder-page[data-builder-step="detalji"] .builder-back-exit {
        display: none;
    }

    /*
     * Beside the arrow, and pushing undo/redo and the toggle to the far edge.
     * A block rather than a flex row, so a longer state than "Sačuvano" ends
     * in an ellipsis instead of being cut off mid-word.
     */
    .builder-autosave-status {
        display: block;
        margin-right: auto;
        margin-left: 0;
        font-size: 0.72rem;
        font-weight: 600;
    }

    /*
     * A tight plate: at 375px the bar has room for "Sačuvano" and its icon only
     * because undo/redo is 34px and the toggle sits one gap from it.
     */
    .builder-autosave-status:not(:empty) {
        padding: 0.25rem 0.3125rem;
    }

    /* A pseudo-element, because builder.js replaces the status's text whole. */
    .builder-autosave-status.is-saved::before {
        display: inline-block;
        width: 15px;
        height: 15px;
        margin-right: 0.3rem;
        background: currentColor;
        vertical-align: -3px;
        content: "";
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m17 15-5.5 5.5L9 18'/%3E%3Cpath d='M5 17.743A7 7 0 1 1 15.71 10h1.79a4.5 4.5 0 0 1 1.5 8.742'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m17 15-5.5 5.5L9 18'/%3E%3Cpath d='M5 17.743A7 7 0 1 1 15.71 10h1.79a4.5 4.5 0 0 1 1.5 8.742'/%3E%3C/svg%3E") center / contain no-repeat;
    }

    .builder-topbar .editor-history-toolbox {
        gap: 2px;
        padding: 2px;
        border-radius: 12px;
    }

    /* Transparent in the white box as drawn, not the browser's grey button face. */
    .builder-topbar .editor-history-toolbox .editor-toolbox-button {
        width: 34px;
        height: 34px;
        min-height: 34px;
        border-radius: 10px;
        background: transparent;
    }

    .builder-topbar .editor-history-toolbox .editor-toolbox-button svg {
        width: 19px;
        height: 19px;
    }

    .builder-topbar .view-mode-toggle-option {
        padding: 0.44rem 0.575rem;
        font-size: 0.8rem;
    }

    .builder-topbar .view-mode-toggle-option svg {
        display: none;
    }

    /* ------------------------------------------ stage: one screen at a time -- */

    .builder-body {
        flex-direction: column;
    }

    .builder-steps,
    .builder-teaser-hit,
    .builder-canvas-hint {
        display: none;
    }

    /* Only Dalje leaves Dizajn; a vertical swipe over the designs does not. */
    .builder-page[data-builder-step="dizajn"] .builder-scroll {
        overflow-y: hidden;
    }

    .builder-section-design {
        flex: 0 0 auto;
        align-items: stretch;
        height: var(--builder-stage-h);
        min-height: 0;
        padding: 0;
    }

    /* Stretched, or each strip would be as wide as everything it scrolls. */
    .builder-design-row {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        height: 100%;
    }

    /*
     * The invitation takes the height the designs and the bar leave and is as
     * wide as that height allows: the whole screen for a 4:5 design on most
     * phones. The column is a size container, so the card is sized against
     * both of its dimensions in CSS rather than from a measured budget that
     * drifts. It sits above the designs and the bar, which the text toolbar's
     * popovers can open over.
     */
    .builder-canvas-col {
        position: relative;
        z-index: 2;
        flex: 1 1 auto;
        justify-content: center;
        width: 100%;
        min-height: 0;
        container-type: size;
    }

    .builder-page .canvas-frame {
        /* Only where container units are missing: the stage less the designs and the bar. */
        width: min(100%, calc((var(--builder-stage-h) - 16.5rem) * var(--invitation-aspect, 0.8)));
        width: min(100cqw, calc(100cqh * var(--invitation-aspect, 0.8)));
    }

    /*
     * Edge to edge the card is square and flat, like a photo. The radius reads
     * how much narrower than the screen it is — none at full width, the usual
     * 14px once a short screen leaves it 1.4px short of the edges.
     */
    .builder-page .invitation-canvas {
        box-shadow: none;
    }

    .builder-page .invitation-canvas,
    .builder-page .invitation-canvas .background-clip {
        border-radius: clamp(0px, (100cqw - 100cqh * var(--invitation-aspect, 0.8)) * 10, 14px);
    }

    /* --------------------------------------------------------- designs -- */

    .builder-gallery {
        flex: 0 0 auto;
        gap: 0.625rem;
        width: auto;
        height: auto;
        padding: 0.625rem 0 0.75rem;
    }

    /*
     * Both strips scroll sideways and fade out at the far edge, which is what
     * says there is more. The fade is a mask, so it works over whatever colour
     * the design has tinted the page, and the end padding lets the last item
     * scroll clear of it. The vertical padding, taken back by the margins, is
     * room for the items' shadows, which a scroller would otherwise clip.
     */
    .builder-gallery-cats,
    .builder-gallery-scroller {
        flex: 0 0 auto;
        flex-direction: row;
        min-width: 0;
        margin: -0.25rem 0 -0.75rem;
        padding: 0.25rem 2rem 0.75rem 0.75rem;
        overflow-x: auto;
        overflow-y: hidden;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
        -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 2rem), transparent);
        mask-image: linear-gradient(90deg, #000 calc(100% - 2rem), transparent);
    }

    .builder-gallery-cats::-webkit-scrollbar,
    .builder-gallery-scroller::-webkit-scrollbar {
        display: none;
    }

    .builder-gallery-cats {
        gap: 0.375rem;
    }

    .builder-gallery-cats .background-template-tab {
        flex: 0 0 auto;
        min-height: 34px;
        padding: 0 0.75rem;
        font-size: 0.75rem;
        white-space: nowrap;
    }

    /*
     * The thumbnails are a grid, so the strip is the grid laid on its side —
     * `grid-auto-flow: column` with fixed cells. Setting flex-direction here
     * does nothing and the strip silently becomes one tall column. The grid is
     * as wide as its cells: at the width of the strip, the cells overflowed a
     * box the end padding followed, and the last design never cleared the fade.
     */
    .builder-page .builder-gallery-scroller .background-grid {
        grid-auto-flow: column;
        grid-template-columns: none;
        grid-auto-columns: 60px;
        justify-content: start;
        width: max-content;
    }

    .builder-page .builder-gallery-scroller .background-choice {
        width: 60px;
        height: 75px;
        min-height: 0;
        margin: 0;
        border-radius: 10px;
    }

    .builder-gallery-cta {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.375rem;
        height: 34px;
        margin: 0 0.75rem;
        padding: 0 0.75rem;
        font-size: 0.72rem;
    }

    /* ---------------------------------------------- the Dodaj and Dalje bar -- */

    .builder-actions {
        display: flex;
        flex: 0 0 auto;
        align-self: stretch;
        align-items: center;
        gap: 0.375rem;
        padding: 0.5rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
        border-top: 1px solid rgba(56, 87, 79, 0.12);
        background: var(--app-panel);
        box-shadow: 0 -6px 18px rgba(37, 61, 54, 0.06);
    }

    .builder-add-rail {
        flex-direction: row;
        gap: 0.375rem;
        padding-top: 0;
    }

    .builder-add-label {
        margin-right: 0.25rem;
        color: var(--app-plum);
        font-size: 0.66rem;
    }

    .builder-add-button {
        gap: 0.25rem;
        width: 56px;
        height: 56px;
        border-color: rgba(56, 87, 79, 0.14);
        background: var(--app-paper);
        font-size: 0.69rem;
        box-shadow: none;
    }

    .builder-next-button {
        display: inline-flex;
    }

    /* --------------------------------------------------------- Detalji -- */

    .builder-details-head-text h1 {
        font-size: 1.25rem;
    }

    .builder-details-thumb {
        width: 72px;
    }
}

/*
 * Below 375px the status plate cannot hold both the icon and "Sačuvano" beside
 * the other controls, and the word says more than the icon.
 */
@media (max-width: 374.98px) {
    .builder-autosave-status.is-saved::before {
        display: none;
    }
}

/*
 * The invitation is the one thing that must never be cut off, so on a short
 * screen the hint under it goes rather than the card getting smaller.
 */
@media (max-height: 600px) {
    .builder-canvas-hint {
        display: none;
    }

    .builder-page {
        --builder-canvas-chrome: 2rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .builder-details-head,
    .builder-step,
    .view-mode-toggle-option,
    .builder-next-button,
    .builder-publish-button {
        transition: none;
    }
}

/* The align button carries all three icons; only the active one shows. */
.editor-toolbox-align [data-align-icon] {
    display: none;
}

.editor-toolbox-align[data-active-align="left"] [data-align-icon="left"],
.editor-toolbox-align[data-active-align="center"] [data-align-icon="center"],
.editor-toolbox-align[data-active-align="right"] [data-align-icon="right"] {
    display: block;
}

/*
 * Potvrda dolaska off dims what it governs, as the redesign draws it. The
 * controls stay disabled by builder.js either way — this only says so.
 */
.builder-card:has(#rsvpEnabled:not(:checked)) .rsvp-builder-groups,
.builder-card:has(#rsvpEnabled:not(:checked)) .rsvp-builder-options {
    opacity: 0.45;
}
