<template>
    <section class="fmt-canvas">
        <header class="fmt-canvas__header">
            <h2>{{ __("Your Form") }}</h2>
            <p>
                {{
                    __(
                        "Reorder fields by drag and drop. Click on the field name to edit its settings.",
                    )
                }}
            </p>
            <div class="fmt-canvas__header-actions">
                <!-- Quick actions (after first save). Copy-shortcode is Free —
                     the basic shortcode works for everyone. The create-page/post
                     deep-links are Pro (forms.quick_actions) and hidden on Free. -->
                <button
                    v-if="hasSavedFormId"
                    type="button"
                    class="button button-secondary fmt-canvas__quick-action"
                    :class="{ 'is-copied': copied }"
                    @click="onShortcodeClick"
                    :title="copied ? __('Copied to clipboard!', 'formatrica') : __('Get shortcode', 'formatrica')"
                    :aria-label="copied ? __('Copied to clipboard!', 'formatrica') : __('Get shortcode', 'formatrica')"
                >
                    <img :src="copied ? ICON_CLIPBOARD_CHECK : ICON_CODE_DOTS" alt="" aria-hidden="true" />
                </button>
                <span v-if="copied" class="fmt-canvas__copied-flash" role="status">{{ __("Copied!", "formatrica") }}</span>
                <button
                    v-if="hasSavedFormId && hasQuickActions"
                    type="button"
                    class="button button-secondary fmt-canvas__quick-action"
                    @click="openCreate('page')"
                    :title="__('Create a page with this form', 'formatrica')"
                    :aria-label="__('Create a page with this form', 'formatrica')"
                >
                    <img :src="ICON_BLOCKS" alt="" aria-hidden="true" />
                </button>
                <button
                    v-if="hasSavedFormId && hasQuickActions"
                    type="button"
                    class="button button-secondary fmt-canvas__quick-action"
                    @click="openCreate('post')"
                    :title="__('Create a post with this form', 'formatrica')"
                    :aria-label="__('Create a post with this form', 'formatrica')"
                >
                    <img :src="ICON_PENCIL" alt="" aria-hidden="true" />
                </button>
                <span
                    v-if="showLayoutToggles"
                    class="fmt-canvas__layout-group"
                    role="group"
                    :aria-label="__('Layout mode', 'formatrica')"
                >
                    <button
                        v-for="opt in layoutToggleOptions"
                        :key="opt.mode"
                        type="button"
                        class="fmt-canvas__layout-toggle"
                        :class="{ 'fmt-canvas__layout-toggle--active': layoutMode === opt.mode }"
                        @click="setLayoutMode(opt.mode)"
                        :title="opt.label"
                        :aria-label="opt.label"
                        :aria-pressed="layoutMode === opt.mode ? 'true' : 'false'"
                    >
                        <img :src="opt.icon" alt="" aria-hidden="true" />
                    </button>
                </span>
                <button
                    type="button"
                    class="button button-secondary fmt-canvas__settings"
                    @click="$emit('open-settings')"
                    :title="__('Form settings', 'formatrica')"
                    :aria-label="__('Form settings', 'formatrica')"
                >
                    <img
                        class="fmt-canvas__settings-icon"
                        :src="ICON_SETTINGS"
                        alt=""
                        aria-hidden="true"
                    />
                </button>
            </div>
        </header>
        <div
            ref="canvasRef"
            class="fmt-canvas__board"
            :class="{
                'fmt-canvas__board--empty': !fields.length,
                'fmt-canvas__board--two-column': layoutMode === 'two_column',
                'fmt-canvas__board--three-column': layoutMode === 'three_column',
            }"
        >
            <div v-if="!fields.length" class="fmt-canvas__empty">
                {{ __("Drag fields here to start building your form.") }}
            </div>
            <article
                v-for="(field, index) in fields"
                :key="field.id"
                class="fmt-field"
                :class="{
                    'fmt-field--selected': field.id === selectedId,
                    'fmt-field--just-added': field.id === justAddedId,
                    'fmt-field--half': usesGridLayout && fieldIsHalf(field),
                    'fmt-field--third': usesGridLayout && fieldIsThird(field),
                }"
                :data-field-id="field.id"
                :data-id="field.id"
            >
                <div class="fmt-field__main" @click="emitSelect(field.id)">
                    <span class="fmt-field__drag" aria-hidden="true">⋮⋮</span>
                    <img
                        class="fmt-field__icon"
                        :src="getIcon(field.type)"
                        alt=""
                        aria-hidden="true"
                    />
                    <div class="fmt-field__content">
                        <button
                            type="button"
                            class="fmt-field__label-button"
                            @click.stop="emitSelect(field.id)"
                            :aria-pressed="field.id === selectedId"
                            :aria-label="field.label ? field.label : __('Edit field', 'formatrica')"
                        >
                            <span class="fmt-field__label-text">{{
                                field.label || __("Label", "formatrica")
                            }}</span>
                            <img class="fmt-field__label-icon" :src="ICON_EDIT" alt="" aria-hidden="true" />
                        </button>
                        <small class="fmt-field__meta">
                            <template v-if="field.type === 'custom_text'">
                                {{ __("Static content", "formatrica") }}
                            </template>
                            <template v-else-if="field.type === 'hidden'">
                                {{ __("Hidden field", "formatrica") }}
                            </template>
                            <template v-else>
                                {{ field.type }} ·
                                {{
                                    field.required
                                        ? __("Required")
                                        : __("Optional")
                                }}
                            </template>
                        </small>
                    </div>
                </div>
                <div class="fmt-field__actions">
                    <button
                        type="button"
                        class="fmt-field__action"
                        :disabled="index === 0"
                        :title="__('Move up', 'formatrica')"
                        :aria-label="__('Move up', 'formatrica')"
                        @click.stop="moveFieldUp(index)"
                    >
                        <img :src="ICON_ARROW_UP" alt="" aria-hidden="true" />
                    </button>
                    <button
                        type="button"
                        class="fmt-field__action"
                        :disabled="index === fields.length - 1"
                        :title="__('Move down', 'formatrica')"
                        :aria-label="__('Move down', 'formatrica')"
                        @click.stop="moveFieldDown(index)"
                    >
                        <img :src="ICON_ARROW_DOWN" alt="" aria-hidden="true" />
                    </button>
                    <button
                        v-if="canToggleWidth && fieldIsGridType(field.type)"
                        type="button"
                        class="fmt-field__action fmt-field__action--width"
                        :class="{
                            'fmt-field__action--width-half': fieldIsHalf(field),
                            'fmt-field__action--width-third': fieldIsThird(field),
                        }"
                        :title="fieldWidthToggleLabel(field)"
                        :aria-label="fieldWidthToggleLabel(field)"
                        @click.stop="cycleFieldWidth(field)"
                    >
                        <img :src="fieldWidthIcon(field)" alt="" aria-hidden="true" />
                    </button>
                    <button
                        type="button"
                        class="fmt-field__action"
                        :title="__('Duplicate')"
                        :aria-label="__('Duplicate')"
                        @click.stop="emitDuplicate(field.id)"
                    >
                        <img :src="ICON_COPY_PLUS" alt="" aria-hidden="true" />
                    </button>
                    <button
                        type="button"
                        class="fmt-field__action fmt-field__action--danger"
                        :title="__('Remove')"
                        :aria-label="__('Remove')"
                        @click.stop="emitRemove(field.id)"
                    >
                        <img :src="ICON_REMOVE" alt="" aria-hidden="true" />
                    </button>
                </div>
            </article>
        </div>
    </section>
</template>

<script setup>
import { computed, onMounted, onBeforeUnmount, nextTick, ref, watch } from "vue";
import Sortable from "sortablejs";
import { __ } from "@/utils/i18n";
import { useFormStore } from "@/admin/stores/formStore";
import { useCapabilities } from "@/admin/composables/useCapabilities";
import { iconUrlForType } from "@/admin/fields/icons";
import { typeFlag } from "@/admin/fields/type-registry";
import ICON_SETTINGS from "../../../assets/icons/settings-cog.svg";
import ICON_EDIT from "../../../assets/icons/edit.svg";
import ICON_COPY_PLUS from "../../../assets/icons/copy-plus.svg";
import ICON_REMOVE from "../../../assets/icons/backspace.svg";
import ICON_CODE_DOTS from "../../../assets/icons/code-dots.svg";
import ICON_CLIPBOARD_CHECK from "../../../assets/icons/clipboard-check.svg";
import ICON_COLUMNS_1 from "../../../assets/icons/columns-1.svg";
import ICON_COLUMNS_2 from "../../../assets/icons/columns-2.svg";
import ICON_COLUMNS_3 from "../../../assets/icons/columns-3.svg";
import ICON_ARROW_UP from "../../../assets/icons/arrow-up.svg";
import ICON_ARROW_DOWN from "../../../assets/icons/arrow-down.svg";
import ICON_BLOCKS from "../../../assets/icons/blocks.svg";
import ICON_PENCIL from "../../../assets/icons/pencil.svg";

const props = defineProps({
    fields: {
        type: Array,
        required: true,
    },
    selectedId: {
        type: String,
        default: null,
    },
});

const emit = defineEmits([
    "select",
    "remove",
    "duplicate",
    "reorder",
    "create-field",
    "open-shortcode",
]);
const canvasRef = ref(null);
let sortableInstance = null;

const store = useFormStore();
const emitSelect = (id) => emit("select", id);
const emitRemove = (id) => emit("remove", id);
const emitDuplicate = (id) => emit("duplicate", id);

const getIcon = (type) => iconUrlForType(type);

// Quick actions (forms.quick_actions) — only render once the form has been
// saved (pre-save there's no id to thread into the deep-link / shortcode).
const { has: hasCapability } = useCapabilities();
// Vite define — a literal after build, so the minifier deletes dead branches.
// eslint-disable-next-line no-undef
const PRO_UI = __FMT_PRO_UI__;

// ---- Layout mode + per-field width ----
const ALLOWED_LAYOUT_MODES = ["single", "two_column", "three_column"];
const layoutMode = computed(() => {
    const mode = store.options?.layout?.mode;
    return ALLOWED_LAYOUT_MODES.includes(mode) ? mode : "single";
});
const usesGridLayout = computed(
    () => layoutMode.value === "two_column" || layoutMode.value === "three_column",
);
// Two/three-column layout is Free — the toggles are always available.
const showLayoutToggles = true;
const layoutToggleOptions = [
    { mode: "single", icon: ICON_COLUMNS_1, label: __("Single column", "formatrica") },
    { mode: "two_column", icon: ICON_COLUMNS_2, label: __("Two columns", "formatrica") },
    { mode: "three_column", icon: ICON_COLUMNS_3, label: __("Three columns", "formatrica") },
];

function setLayoutMode(mode) {
    if (!ALLOWED_LAYOUT_MODES.includes(mode)) {
        return;
    }
    if (!store.options.layout || typeof store.options.layout !== "object") {
        store.options.layout = {};
    }
    if (store.options.layout.mode === mode) {
        return;
    }
    store.options.layout.mode = mode;
    store.hasUnsavedChanges = true;
}

// Mirrors the drawer's supportsWidth (registry `grid` flag; unknown/preserved
// types participate, matching pre-registry behavior).
function fieldIsGridType(type) {
    return typeFlag(type, "grid", true);
}
function fieldIsHalf(field) {
    return fieldIsGridType(field.type) && field.layout?.width === "half";
}
function fieldIsThird(field) {
    return fieldIsGridType(field.type) && field.layout?.width === "third";
}
// The quick width toggle is available whenever the form uses a grid layout.
const canToggleWidth = computed(() => usesGridLayout.value);

// Quick toggle: binary full <-> half in two-column mode, 3-way cycle
// full -> half -> third -> full in three-column.
function cycleFieldWidth(field) {
    if (!field.layout || typeof field.layout !== "object") {
        field.layout = {};
    }
    const current = field.layout.width || "full";
    let next;
    if (layoutMode.value === "three_column") {
        next = current === "full" ? "half" : current === "half" ? "third" : "full";
    } else {
        next = current === "half" ? "full" : "half";
    }
    field.layout.width = next;
    store.hasUnsavedChanges = true;
}
function fieldWidthIcon(field) {
    if (fieldIsThird(field)) {
        return ICON_COLUMNS_3;
    }
    if (fieldIsHalf(field)) {
        return ICON_COLUMNS_2;
    }
    return ICON_COLUMNS_1;
}
function fieldWidthToggleLabel(field) {
    if (fieldIsThird(field)) {
        return __("Width: third", "formatrica");
    }
    if (fieldIsHalf(field)) {
        return __("Width: half", "formatrica");
    }
    return __("Width: full", "formatrica");
}

// Explicit reorder buttons alongside drag-and-drop.
function moveFieldUp(index) {
    if (index > 0) {
        emit("reorder", { oldIndex: index, newIndex: index - 1 });
    }
}
function moveFieldDown(index) {
    if (index < props.fields.length - 1) {
        emit("reorder", { oldIndex: index, newIndex: index + 1 });
    }
}
const hasQuickActions = hasCapability("forms.quick_actions");
const hasSavedFormId = computed(() => Number(store.formId) > 0);
const quickActionUrls = window.formatrica?.builder?.quickActions || {};


const openCreate = (type) => {
    const base = type === "page" ? quickActionUrls.newPageUrl : quickActionUrls.newPostUrl;
    if (!base || !hasSavedFormId.value) {
        return;
    }
    const sep = base.includes("?") ? "&" : "?";
    window.open(`${base}${sep}formatrica_form_id=${Number(store.formId)}`, "_blank", "noopener");
};

// "Just added" affordance: when the store signals a new field id (set inside
// addField/duplicateField), scroll the matching card into view and flash a glow
// for ~1.5s. Especially useful when the new field lands below the fold — without
// it the admin clicks the palette and nothing visible happens.
const justAddedId = ref(null);
let justAddedTimer = null;
let copiedTimer = null;
const copied = ref(false);

// Free bundle: "Get shortcode" copies the basic shortcode to the clipboard and
// flashes a confirmation. Full bundle: it opens the shortcode generator modal.
const onShortcodeClick = () => {
    if (PRO_UI) {
        emit("open-shortcode");
        return;
    }
    copyShortcode();
};
const copyShortcode = async () => {
    const shortcode = `[formatrica id="${Number(store.formId)}"]`;
    try {
        if (navigator.clipboard?.writeText) {
            await navigator.clipboard.writeText(shortcode);
        }
    } catch (e) {
        // Clipboard may be unavailable in some contexts; the flash still confirms.
    }
    copied.value = true;
    if (copiedTimer) {
        clearTimeout(copiedTimer);
    }
    copiedTimer = setTimeout(() => {
        copied.value = false;
        copiedTimer = null;
    }, 2000);
};

watch(
    () => store.lastAddedFieldId,
    (newId) => {
        if (!newId) {
            return;
        }
        justAddedId.value = newId;
        // Clear the store-side signal so a subsequent add of the same type
        // re-triggers, and the watcher doesn't fire on unrelated state changes.
        store.acknowledgeAddedField();

        nextTick(() => {
            const el = canvasRef.value
                ? canvasRef.value.querySelector(`[data-field-id="${newId}"]`)
                : null;
            if (el && typeof el.scrollIntoView === "function") {
                el.scrollIntoView({ behavior: "smooth", block: "center" });
            }
        });

        if (justAddedTimer) {
            clearTimeout(justAddedTimer);
        }
        justAddedTimer = setTimeout(() => {
            justAddedId.value = null;
            justAddedTimer = null;
        }, 1500);
    },
);

onMounted(() => {
    if (!canvasRef.value) {
        return;
    }

    sortableInstance = Sortable.create(canvasRef.value, {
        group: {
            name: "fmt-fields",
            pull: true,
            // Reject drops of anything that isn't a real palette tile
            // (data-field-type) or an in-canvas reorder (data-field-id). The
            // browser's native image drag can otherwise leak an orphan node.
            put: (_to, _from, dragEl) => {
                if (!dragEl) return true;
                if (dragEl.dataset?.fieldId) return true;
                return Boolean(dragEl.dataset?.fieldType);
            },
        },
        handle: ".fmt-field__drag",
        animation: 160,
        easing: "cubic-bezier(0.2, 0, 0, 1)",
        ghostClass: "fmt-field--ghost",
        chosenClass: "fmt-field--chosen",
        dragClass: "fmt-field--drag",
        // Mobile: 200ms long-press before a reorder drag activates, so a finger
        // swipe scrolls the canvas instead of grabbing a card. Desktop mouse
        // drag stays instant (delayOnTouchOnly).
        delay: 200,
        delayOnTouchOnly: true,
        touchStartThreshold: 5,
        onAdd(evt) {
            // Remove the foreign Sortable node from the Vue-owned list FIRST,
            // then emit create-field — emitting first would let store.addField
            // mutate state while the orphan node still sits in the canvas DOM.
            const type = evt.item?.dataset?.fieldType;
            const index = typeof evt.newIndex === "number" ? evt.newIndex : null;
            if (evt.item && evt.item.parentNode) {
                evt.item.parentNode.removeChild(evt.item);
            }
            if (type) {
                // Insert where the tile was dropped; a plain palette CLICK
                // still appends (that path doesn't come through here).
                emit("create-field", { type, index });
            }
        },
        onEnd(evt) {
            if (
                typeof evt.oldIndex === "undefined" ||
                typeof evt.newIndex === "undefined"
            ) {
                return;
            }
            if (evt.from !== evt.to) {
                return;
            }
            if (evt.oldIndex === evt.newIndex) {
                return;
            }
            emit("reorder", {
                oldIndex: evt.oldIndex,
                newIndex: evt.newIndex,
            });
        },
    });
});

onBeforeUnmount(() => {
    if (sortableInstance) {
        sortableInstance.destroy();
        sortableInstance = null;
    }
    if (justAddedTimer) {
        clearTimeout(justAddedTimer);
        justAddedTimer = null;
    }
    if (copiedTimer) {
        clearTimeout(copiedTimer);
        copiedTimer = null;
    }
});

// Re-sync SortableJS's DOM order to the store after a structural change.
// MUST run post-render: the newly added card has to exist in the DOM before we
// reorder. Reordering pre-render (Vue's default flush) detaches the existing
// nodes mid-patch, so Vue's keyed insert lands the fresh card at the TOP instead
// of the bottom — the palette-add-goes-to-top bug. flush:"post" makes this a
// harmless no-op once Vue has already appended the card in array order.
watch(
    () => props.fields.map((f) => f.id).join(','),
    () => {
        if (!sortableInstance) return;
        sortableInstance.sort(props.fields.map((field) => field.id));
    },
    { flush: "post" },
);
</script>

<style scoped>
.fmt-canvas {
    container-type: inline-size;
    container-name: canvas;
    background: #fff;
    border: 1px solid #dcdcde;
    border-radius: 10px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    height: 100%;
    /* Constrain height so side panels (like the field palette) can scroll internally */
    min-height: 520px;
    /* Tweak these offsets if WP admin bars/toolbars change
       Subtract the WP admin footer safe area (~65px) to avoid bottom cut-off */
    max-height: calc(100vh - 180px - 65px);
    overflow: hidden;
}

.fmt-canvas__header h2 {
    margin: 0;
    font-size: 1.25rem;
}

.fmt-canvas__header {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: start;
    gap: 4px 12px;
    position: relative;
}

.fmt-canvas__header h2 {
    grid-column: 1 / 2;
}

.fmt-canvas__header p {
    margin: 4px 0 12px;
    color: #6c757d;
    font-size: 1rem;
    grid-column: 1 / 2;
}

.fmt-canvas__copied-flash {
    align-self: center;
    font-size: 12px;
    font-weight: 600;
    color: #1e8a4c;
    white-space: nowrap;
}

.fmt-canvas__header-actions {
    grid-column: 2 / 3;
    justify-self: end;
    align-self: start;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    position: absolute;
    top: -10px;
    right: -10px;
}

.fmt-canvas__quick-action,
.fmt-canvas__settings {
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 50%;
    background: transparent;
    border: none;
}

.fmt-canvas__quick-action img {
    width: 20px;
    height: 20px;
}

.fmt-canvas__quick-action:hover {
    background: #f0f0f1;
}

.fmt-canvas__settings:focus {
    outline-offset: 2px;
}
.fmt-canvas__settings:hover {
    background: #f0f0f1;
}

.fmt-canvas__board {
    flex: 1;
    border: 1px dashed #dcdcde;
    border-radius: 10px;
    padding: 12px;
    max-height: inherit;
    overflow: auto;
}

.fmt-canvas__board--empty {
    display: flex;
    align-items: center;
    justify-content: center;
}

.fmt-canvas__empty {
    color: #6c757d;
    font-size: 1.05rem;
    text-align: center;
}

.fmt-field {
    container-type: inline-size;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border: 1px solid #e2e4e7;
    border-radius: 8px;
    padding: 10px 12px;
    background: #fff;
    margin-bottom: 8px;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.fmt-field:hover {
    border-color: #c3c4c7;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.fmt-field:last-child {
    margin-bottom: 0;
}

.fmt-field--selected,
.fmt-field--selected:hover {
    border-color: #2271b1;
    box-shadow: inset 3px 0 0 #2271b1, 0 1px 3px rgba(34, 113, 177, 0.12);
}

.fmt-field--ghost {
    opacity: 0.4;
}

/* The card being dragged (dragClass) — lift + subtle rotate for a tactile feel.
   The chosen source stays crisp; the ghost placeholder is the faded slot. */
.fmt-field--drag {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    opacity: 0.95;
}

.fmt-field--chosen {
    cursor: grabbing;
}

/* "Just added" glow — a 1.5s pulse that draws the eye to the new card after the
   canvas auto-scrolls to it. */
.fmt-field--just-added {
    animation: fmt-field-just-added-glow 1.5s ease-out;
}

@keyframes fmt-field-just-added-glow {
    0% {
        box-shadow: 0 0 0 0 #2271b1;
        border-color: #2271b1;
    }
    30% {
        box-shadow: 0 0 0 6px rgba(34, 113, 177, 0.35);
        border-color: #2271b1;
    }
    100% {
        box-shadow: 0 0 0 0 rgba(34, 113, 177, 0);
        border-color: #e2e4e7;
    }
}

.fmt-field__main {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
}

.fmt-field__drag {
    font-size: 1.2rem;
    cursor: grab;
    color: #646970;
}

.fmt-field__content {
    display: flex;
    flex-direction: column;
}

.fmt-field__content strong {
    font-size: 1.05rem;
}

.fmt-field__meta {
    color: #6c757d;
    font-size: 0.9rem;
}

.fmt-field__actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

.fmt-field__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid #e2e4e7;
    border-radius: 6px;
    background: #fff;
    color: #50575e;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.fmt-field__action img {
    width: 17px;
    height: 17px;
    display: block;
}

.fmt-field__action:hover {
    background: #f0f0f1;
    border-color: #c3c4c7;
}

/* Red remove icon (black -> danger red). */
.fmt-field__action--danger > img {
    filter: invert(15%) sepia(95%) saturate(6932%) hue-rotate(358deg) brightness(95%) contrast(112%);
}

.fmt-field__action--danger:hover {
    background: rgba(220, 53, 69, 0.12);
    border-color: rgba(220, 53, 69, 0.35);
}

.fmt-field__action:focus-visible {
    outline: 2px solid #2271b1;
    outline-offset: 1px;
}

.fmt-field__label-button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    color: inherit;
    cursor: pointer;
    text-align: left;
}

.fmt-field__label-button:focus {
    outline: 2px solid #2271b1;
    outline-offset: 2px;
    border-radius: 4px;
}

.fmt-field__label-button .fmt-field__label-text{
    font-weight: 600;
    font-size: 1rem;
}

.fmt-field__label-button:hover .fmt-field__label-text {
    text-decoration: underline;
}

.fmt-field__label-icon {
    width: 14px;
    height: 14px;
    opacity: 0.85;
}

.fmt-field__icon {
    width: 20px;
    height: 20px;
    opacity: 0.9;
}

.fmt-canvas__settings-icon {
    width: 26px;
    height: 26px;
}

.fmt-canvas__layout-group {
    display: inline-flex;
    gap: 4px;
    margin-right: 6px;
}

.fmt-canvas__layout-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid #c3c4c7;
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
}

.fmt-canvas__layout-toggle img {
    width: 16px;
    height: 16px;
}

.fmt-canvas__layout-toggle--active {
    border-color: #2271b1;
    background: #f0f6fc;
    box-shadow: inset 0 0 0 1px #2271b1;
}

.fmt-canvas__layout-toggle:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Multi-column canvas mirrors the frontend's 12-track model so half (6/12)
   and third (4/12) line up identically in builder and page. */
.fmt-canvas__board--two-column,
.fmt-canvas__board--three-column {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 8px;
    align-content: start;
}

.fmt-canvas__board--two-column .fmt-field,
.fmt-canvas__board--three-column .fmt-field {
    grid-column: 1 / -1;
    margin-bottom: 0;
}

/* SortableJS clones a palette tile into the board mid-drag; force it to span
   the full row so the drop preview matches a real card's shape. */
.fmt-canvas__board--two-column > .fmt-panel__item,
.fmt-canvas__board--three-column > .fmt-panel__item {
    grid-column: 1 / -1;
}

.fmt-canvas__board--two-column .fmt-field--half,
.fmt-canvas__board--two-column .fmt-field--third {
    grid-column: span 6;
}

.fmt-canvas__board--three-column .fmt-field--half {
    grid-column: span 8;
}

.fmt-canvas__board--three-column .fmt-field--third {
    grid-column: span 4;
}

/* Narrow canvas (sidebar open, pinned preview, phone): collapse the board to
   one track; span rules clamp to 1 automatically. */
@container canvas (max-width: 800px) {
    .fmt-canvas__board--two-column,
    .fmt-canvas__board--three-column {
        grid-template-columns: 1fr;
    }
    .fmt-canvas__board--two-column .fmt-field,
    .fmt-canvas__board--three-column .fmt-field {
        grid-column: 1 / -1;
    }
}

/* Belt-and-suspenders viewport fallback. */
@media (max-width: 991.98px) {
    .fmt-canvas__board--two-column,
    .fmt-canvas__board--three-column {
        grid-template-columns: 1fr;
    }
    .fmt-canvas__board--two-column .fmt-field,
    .fmt-canvas__board--three-column .fmt-field {
        grid-column: 1 / -1;
    }
}

/* Narrow card (per-card container query): stack the title row over the
   action row so buttons never overflow. */
@container (max-width: 450px) {
    .fmt-field {
        flex-wrap: wrap;
    }
    .fmt-field__main {
        flex: 1 1 100%;
    }
    .fmt-field__actions {
        flex: 1 1 100%;
        margin-left: 0;
        margin-top: 8px;
        justify-content: flex-end;
        padding-right: 12px;
    }
}

/* ---- Mobile canvas ---- */
@media (max-width: 767.98px) {
    .fmt-field__drag {
        display: none; /* touch reorders via the up/down buttons */
    }
    .fmt-field {
        flex-wrap: wrap;
    }
    .fmt-field__main {
        flex: 1 1 100%;
    }
    .fmt-field__actions {
        flex: 1 1 100%;
        margin-left: 0;
        margin-top: 8px;
        justify-content: flex-end;
    }
    .fmt-canvas {
        padding: 12px;
        min-height: auto;
        max-height: none;
    }
    .fmt-canvas__board {
        padding-bottom: 140px; /* keep the add-field FAB off the last card */
    }
}

.fmt-field__action--width-half {
    border-color: #2271b1;
}

.fmt-field__action--width-third {
    border-color: #8b5cf6;
}
</style>
