<script setup>
import { computed, onMounted, onUnmounted, provide, reactive, ref, watch } from 'vue';
import ImageDropZone from './components/ImageDropZone.vue';
import RichTextEditor from './components/RichTextEditor.vue';
import ProjectPageRenderer from './ProjectPageRenderer.vue';
import {
    PROJECT_SCHEMA_EXAMPLE,
    blockTypeOptions,
    buildInitialProject,
    createBlock,
    mediaTypeOptions,
    serializeProjectSchema,
} from './schema/projectSchema';

const props = defineProps({
    initialProject: {
        type: Object,
        default: () => ({}),
    },
    fieldId: {
        type: String,
        default: 'project-structure-field',
    },
    uploadUrl: {
        type: String,
        default: null,
    },
    languages: {
        type: Array,
        default: () => [],
    },
    defaultLanguage: {
        type: String,
        default: '',
    },
    categories: {
        type: Array,
        default: () => [],
    },
    activeValue: {
        default: 1,
    },
});

const HERO_ID = '__hero__';

const project = ref(buildInitialProject(props.initialProject));
const selectedBlockId = ref(HERO_ID);
const isHeroSelected = computed(() => selectedBlockId.value === HERO_ID);
const showJson = ref(false);
const showSort = ref(false);
const showSettings = ref(false);
const showProjectSettings = ref(false);
const mobilePreview = ref(false);

// --- Picture upload drop zones ---
const coverInputRef = ref(null);
const ogInputRef = ref(null);
const coverPreview = ref(props.initialProject?.legacy?.pictureCover || null);
const ogPreview = ref(props.initialProject?.legacy?.pictureCatalog || null);
const coverDragOver = ref(false);
const ogDragOver = ref(false);

watch(
    () => project.value.thumbnailMedia?.type,
    (type) => {
        if (!project.value.thumbnailMedia) {
            project.value.thumbnailMedia = { type: 'image', url: '', poster: '', autoplay: false, loop: false, muted: false };
        }

        if (type === 'bunny') {
            project.value.thumbnailMedia.autoplay = true;
            project.value.thumbnailMedia.loop = true;
            project.value.thumbnailMedia.muted = true;
            return;
        }

        project.value.thumbnailMedia.url = '';
        project.value.thumbnailMedia.poster = '';
        project.value.thumbnailMedia.autoplay = false;
        project.value.thumbnailMedia.loop = false;
        project.value.thumbnailMedia.muted = false;
    },
    { immediate: true },
);

const assignFileToInput = (inputEl, file, previewRef) => {
    if (!file || !file.type.startsWith('image/')) return;
    // Set file on the native input so it is included in form submission
    const dt = new DataTransfer();
    dt.items.add(file);
    inputEl.files = dt.files;
    // Show preview
    if (previewRef.value && previewRef.value.startsWith('blob:')) {
        URL.revokeObjectURL(previewRef.value);
    }
    previewRef.value = URL.createObjectURL(file);
};

const onCoverDrop = (e) => {
    e.preventDefault(); coverDragOver.value = false;
    assignFileToInput(coverInputRef.value, e.dataTransfer?.files?.[0], coverPreview);
};
const onOgDrop = (e) => {
    e.preventDefault(); ogDragOver.value = false;
    assignFileToInput(ogInputRef.value, e.dataTransfer?.files?.[0], ogPreview);
};
const onCoverChange = (e) => {
    const f = e.target.files?.[0]; if (f) {
        if (coverPreview.value?.startsWith('blob:')) URL.revokeObjectURL(coverPreview.value);
        coverPreview.value = URL.createObjectURL(f);
    }
};
const onOgChange = (e) => {
    const f = e.target.files?.[0]; if (f) {
        if (ogPreview.value?.startsWith('blob:')) URL.revokeObjectURL(ogPreview.value);
        ogPreview.value = URL.createObjectURL(f);
    }
};
const clearCover = (e) => { e.stopPropagation(); coverPreview.value = null; if (coverInputRef.value) coverInputRef.value.value = ''; };
const clearOg = (e) => { e.stopPropagation(); ogPreview.value = null; if (ogInputRef.value) ogInputRef.value.value = ''; };

// --- Active ---
const isActive = ref(!!Number(props.activeValue));

// --- Categories ---
const categoryChecked = reactive(
    Object.fromEntries((props.categories || []).map((c) => [c.id, c.checked === true]))
);
const categoriesTouched = ref(false);

// --- Multi-language ---
const selectedLang = ref(props.defaultLanguage || props.languages[0]?.iso || '');

// Initialize allTranslations with an entry for every language
const initTranslations = () => {
    const base = props.initialProject?.translations || {};
    const out = {};
    const langs = props.languages.length ? props.languages : (selectedLang.value ? [{ iso: selectedLang.value }] : []);
    for (const lang of langs) {
        out[lang.iso] = {
            headline: '',
            subline: '',
            clientName: '',
            year: '',
            content: '',
            description: '',
            awarded: [],
            pageTitle: '',
            metaTitle: '',
            metaDescription: '',
            ogTitle: '',
            ogDescription: '',
            ...( base[lang.iso] || {}),
        };
    }
    return out;
};
const allTranslations = ref(initTranslations());

const currentTranslation = computed(() => {
    if (!allTranslations.value[selectedLang.value]) {
        allTranslations.value[selectedLang.value] = { headline: '', subline: '', clientName: '', year: '', content: '', description: '', awarded: [], pageTitle: '', metaTitle: '', metaDescription: '', ogTitle: '', ogDescription: '' };
    }
    return allTranslations.value[selectedLang.value];
});

const awardedText = computed({
    get: () => (currentTranslation.value.awarded || []).join('\n'),
    set: (value) => {
        currentTranslation.value.awarded = value.split('\n').map((s) => s.trim()).filter(Boolean);
    },
});

const previewProject = computed(() => {
    const t = allTranslations.value[selectedLang.value] || {};
    return {
        ...project.value,
        // Keep hidden blocks visible in editor — they just won't appear on the frontend
        contentBlocks: project.value.contentBlocks,
        header: { headline: t.headline || '', subline: t.subline || '' },
        metadata: {
            clientName: t.clientName || '',
            awarded: t.awarded?.length ? t.awarded : [],
            description: t.description || '',
        },
    };
});
// ----------------------

const selectedBlock = computed(() => project.value.contentBlocks.find((block) => block.id === selectedBlockId.value) ?? null);
const selectedBlockIndex = computed(() => project.value.contentBlocks.findIndex((b) => b.id === selectedBlockId.value));

// Provide upload context so preview block components can accept drag-drop directly
provide('editorUploadUrl', computed(() => props.uploadUrl));

// Track pending uploads so the parent form can be blocked while images are in flight
const pendingUploads = ref(0);
provide('editorPendingUploads', pendingUploads);

provide('editorUpdateBlockImage', (blockId, field, index, url) => {
    const block = project.value.contentBlocks.find((b) => b.id === blockId);
    if (!block) return;
    // Legacy
    if (field === 'image') block.image.url = url;
    else if (field === 'images') block.images[index].url = url;
    else if (field === 'poster') block.media.poster = url;
    // New slot-based
    else if (field === 'slot') block.slot.image.url = url;
    else if (field === 'left') block.left.image.url = url;
    else if (field === 'right') block.right.image.url = url;
});
provide('editorUpdateHeroImage', (url) => {
    project.value.heroMedia.url = url;
});

provide('editorUpdateMetadata', (field, value) => {
    if (currentTranslation.value) {
        currentTranslation.value[field] = value;
    }
});

provide('editorUpdateHeader', (field, value) => {
    if (currentTranslation.value) {
        currentTranslation.value[field] = value;
    }
});

provide('editorToggleBlockVisibility', (blockId) => {
    const b = project.value.contentBlocks.find((bl) => bl.id === blockId);
    if (b) b.hidden = !b.hidden;
});

provide('editorSwapBlockColumns', (blockId) => {
    const b = project.value.contentBlocks.find((bl) => bl.id === blockId);
    if (b && b.left !== undefined && b.right !== undefined) {
        const tmp = b.left;
        b.left = b.right;
        b.right = tmp;
    }
});

const scrollToBlock = (blockId) => {
    // Use nextTick so the canvas has rendered if visibility just changed
    const el = document.querySelector(`[data-block-id="${blockId}"]`);
    if (!el) return;
    // Ensure the scroll container honours smooth behaviour
    document.documentElement.style.scrollBehavior = 'smooth';
    el.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

const serializedProject = computed(() => serializeProjectSchema(project.value));

// Dirty tracking — becomes true after the first user-driven change.
const isDirty = ref(false);
let _initialSerialized = null;

watch(
    serializedProject,
    (value, oldValue) => {
        const field = document.getElementById(props.fieldId);
        if (field) {
            field.value = value;
        }
        // Capture baseline on first run (immediate); mark dirty on subsequent changes.
        if (_initialSerialized === null) {
            _initialSerialized = value;
        } else if (value !== _initialSerialized) {
            isDirty.value = true;
        }
    },
    { immediate: true }
);

// Also mark dirty when translation fields change (they are not in serializedProject).
watch(allTranslations, () => { isDirty.value = true; }, { deep: true });

// Block the parent <form> from submitting while any image upload is still in progress
let _parentForm = null;
let _formId = null;

const getFormSubmitButtons = () => {
    const buttons = [];
    if (_parentForm) {
        _parentForm.querySelectorAll('[type="submit"]').forEach((el) => buttons.push(el));
    }
    if (_formId) {
        document.querySelectorAll(`[type="submit"][form="${_formId}"]`).forEach((el) => {
            if (!buttons.includes(el)) buttons.push(el);
        });
    }
    return buttons;
};

const handleFormSubmit = (event) => {
    // Check for pending uploads first
    if (pendingUploads.value > 0) {
        event.preventDefault();
        event.stopImmediatePropagation();
        if (window.toastr) {
            toastr.error(
                `${pendingUploads.value} image${pendingUploads.value > 1 ? 's are' : ' is'} still uploading. Please wait before saving.`,
                'Upload in progress'
            );
        }
        return;
    }

    // Secondary safety check: scan the serialized JSON for any blob: URLs that
    // somehow slipped through (e.g. uploaded without an endpoint configured).
    const json = serializedProject.value || '';
    const blobMatches = json.match(/"blob:[^"]+"/g);
    if (blobMatches) {
        event.preventDefault();
        event.stopImmediatePropagation();
        if (window.toastr) {
            toastr.error(
                `${blobMatches.length} image${blobMatches.length > 1 ? 's have' : ' has'} not finished uploading to the server yet. Please wait and try again.`,
                'Unsaved images detected'
            );
        }
    }
};

watch(pendingUploads, (count) => {
    const buttons = getFormSubmitButtons();
    buttons.forEach((btn) => {
        if (count > 0) {
            btn.disabled = true;
            btn.dataset.uploadsPending = '1';
        } else {
            btn.disabled = false;
            delete btn.dataset.uploadsPending;
        }
    });
});

const handleBeforeUnload = (event) => {
    if (!isDirty.value) return;
    event.preventDefault();
    // Required for legacy browser support; modern browsers show their own message.
    event.returnValue = '';
};

const handleFormSave = () => {
    // Allow navigation after a successful save by clearing the dirty flag.
    if (pendingUploads.value === 0) {
        isDirty.value = false;
    }
};

onMounted(() => {
    const field = document.getElementById(props.fieldId);
    const form = field?.closest('form');
    if (!form) return;
    _parentForm = form;
    _formId = form.id || null;
    _parentForm.addEventListener('submit', handleFormSubmit);
    _parentForm.addEventListener('submit', handleFormSave);
    window.addEventListener('beforeunload', handleBeforeUnload);
});
onUnmounted(() => {
    if (_parentForm) {
        _parentForm.removeEventListener('submit', handleFormSubmit);
        _parentForm.removeEventListener('submit', handleFormSave);
        _parentForm = null;
    }
    _formId = null;
    window.removeEventListener('beforeunload', handleBeforeUnload);
});

const SLOT_ICONS = {
    image: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`,
    text:  `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>`,
    video: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>`,
};

const LAYOUT_ICONS = {
    TwoColumns: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="9" height="18" rx="1"/><rect x="13" y="3" width="9" height="18" rx="1"/></svg>`,
    FullWidth:  `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="18" rx="1"/></svg>`,
};

const blockLabel = (block) => {
    const prefix = block.name ? `${block.name} — ` : '';
    if (block.type === 'FullWidth') return `${prefix}Full Width · ${block.slot?.type ?? '?'}`;
    if (block.type === 'TwoColumns') return `${prefix}Two Columns · ${block.left?.type ?? '?'} / ${block.right?.type ?? '?'}`;
    return `${prefix}${block.type}`;
};

const selectBlock = (blockId) => {
    selectedBlockId.value = blockId;
    showSort.value = false;
    showSettings.value = false;
    showProjectSettings.value = false;
};

const addBlock = (type) => {
    const block = createBlock(type);
    project.value.contentBlocks.push(block);
    selectedBlockId.value = block.id;
};

const removeSelectedBlock = () => {
    if (!selectedBlock.value) {
        return;
    }

    project.value.contentBlocks = project.value.contentBlocks.filter((block) => block.id !== selectedBlock.value.id);
    selectedBlockId.value = project.value.contentBlocks[0]?.id ?? null;
};

const moveSelectedBlock = (direction) => {
    if (!selectedBlock.value) {
        return;
    }

    const currentIndex = project.value.contentBlocks.findIndex((block) => block.id === selectedBlock.value.id);
    const nextIndex = currentIndex + direction;

    if (currentIndex < 0 || nextIndex < 0 || nextIndex >= project.value.contentBlocks.length) {
        return;
    }

    const copy = [...project.value.contentBlocks];
    const [item] = copy.splice(currentIndex, 1);
    copy.splice(nextIndex, 0, item);
    project.value.contentBlocks = copy;
};

const loadExampleSchema = () => {
    project.value = buildInitialProject(PROJECT_SCHEMA_EXAMPLE);
    selectedBlockId.value = project.value.contentBlocks[0]?.id ?? null;
};

// --- Drag-and-drop sorting ---
const dragSrcId = ref(null);
const dragOverId = ref(null);

const onDragStart = (event, blockId) => {
    dragSrcId.value = blockId;
    event.dataTransfer.effectAllowed = 'move';
};

const onDragOver = (event, blockId) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
    dragOverId.value = blockId;
};

const onDragLeave = () => {
    dragOverId.value = null;
};

const onDrop = (event, targetId) => {
    event.preventDefault();
    dragOverId.value = null;

    if (!dragSrcId.value || dragSrcId.value === targetId) {
        return;
    }

    const blocks = [...project.value.contentBlocks];
    const srcIndex = blocks.findIndex((b) => b.id === dragSrcId.value);
    const targetIndex = blocks.findIndex((b) => b.id === targetId);

    if (srcIndex < 0 || targetIndex < 0) {
        return;
    }

    const [item] = blocks.splice(srcIndex, 1);
    blocks.splice(targetIndex, 0, item);
    project.value.contentBlocks = blocks;
};

const onDragEnd = () => {
    dragSrcId.value = null;
    dragOverId.value = null;
};

// Provide block-sort handlers so ProjectBlockRenderer can wire them in the preview
provide('editorBlockDrag', { dragSrcId, dragOverId, onDragStart, onDragOver, onDragLeave, onDrop, onDragEnd });

</script>

<template>
    <div class="project-editor">
        <div v-if="pendingUploads > 0" class="project-editor__upload-notice">
            <span class="project-editor__upload-spinner"></span>
            Uploading {{ pendingUploads }} image{{ pendingUploads > 1 ? 's' : '' }}… please wait before saving.
        </div>
        <aside class="project-editor__controls">
            <!-- Hidden inputs: always in DOM for form submission regardless of selected block -->
            <input type="hidden" name="active" :value="isActive ? '1' : '0'">
            <input type="hidden" name="categories_touched" :value="categoriesTouched ? '1' : '0'">
            <template v-for="cat in props.categories" :key="`category-hidden-${cat.id}`">
                <input v-if="categoryChecked[cat.id]" type="hidden" name="categories[]" :value="cat.id">
            </template>
            <template v-for="(t, iso) in allTranslations" :key="iso">
                <input type="hidden" :name="`prevod[${iso}][headline]`" :value="t.headline || ''">
                <input type="hidden" :name="`prevod[${iso}][subline]`" :value="t.subline || ''">
                <input type="hidden" :name="`prevod[${iso}][name]`" :value="t.clientName || ''">
                <input type="hidden" :name="`prevod[${iso}][year]`" :value="t.year || ''">
                <input type="hidden" :name="`prevod[${iso}][content]`" :value="t.content || ''">
                <input type="hidden" :name="`prevod[${iso}][preview]`" :value="t.description || ''">
                <input type="hidden" :name="`prevod[${iso}][tag1]`" :value="(t.awarded || [])[0] || ''">
                <input type="hidden" :name="`prevod[${iso}][tag2]`" :value="(t.awarded || [])[1] || ''">
                <input type="hidden" :name="`prevod[${iso}][tag3]`" :value="(t.awarded || [])[2] || ''">
                <input type="hidden" :name="`prevod[${iso}][page_title]`" :value="t.pageTitle || ''">
                <input type="hidden" :name="`prevod[${iso}][meta_title]`" :value="t.metaTitle || ''">
                <input type="hidden" :name="`prevod[${iso}][meta_description]`" :value="t.metaDescription || ''">
                <input type="hidden" :name="`prevod[${iso}][og_title]`" :value="t.ogTitle || ''">
                <input type="hidden" :name="`prevod[${iso}][og_description]`" :value="t.ogDescription || ''">
            </template>

        </aside>

        <div
            class="project-editor__preview"
        >

            <div class="project-editor__preview-blocks">
                <div class="project-editor__preview-blocks__bottom">
                    <div v-if="languages.length > 1" class="project-editor__lang-tabs project-editor__lang-tabs--preview">
                        <span class="project-editor__lang-label">Preview lang:</span>
                        <button
                            v-for="lang in languages"
                            :key="lang.iso"
                            type="button"
                            class="project-editor__lang-tab"
                            :class="{ 'project-editor__lang-tab--active': selectedLang === lang.iso }"
                            @click="selectedLang = lang.iso"
                        >{{ lang.iso.toUpperCase() }}</button>
                    </div>
                    <div class="project-editor__toolbar-actions">
                        <button
                            type="button"
                            class="project-editor__sort-btn"
                            :class="{ 'project-editor__sort-btn--active': showSort }"
                            @click="showSort = !showSort; showSettings = false; showProjectSettings = false"
                            title="Reorder blocks"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
                            Sort
                        </button>
                        <button
                            type="button"
                            class="project-editor__sort-btn"
                            :class="{ 'project-editor__sort-btn--active': showSettings }"
                            @click="showSettings = !showSettings; showSort = false; showProjectSettings = false"
                            title="SEO & meta"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
                            Meta
                        </button>
                        <button
                            type="button"
                            class="project-editor__sort-btn"
                            :class="{ 'project-editor__sort-btn--active': showProjectSettings }"
                            @click="showProjectSettings = !showProjectSettings; showSort = false; showSettings = false"
                            title="Categories & visibility"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>
                            Settings
                        </button>
                        <button
                            type="button"
                            class="project-editor__sort-btn"
                            :class="{ 'project-editor__sort-btn--active': mobilePreview }"
                            @click="mobilePreview = !mobilePreview"
                            title="Toggle mobile preview"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
                            Mobile
                        </button>
                    </div>
                </div>
            </div>

            <div class="project-editor__renderer-wrap" :class="{ 'project-editor__renderer-wrap--mobile': mobilePreview }">
            <ProjectPageRenderer
                :project="previewProject"
                :editable="true"
                :selected-block-id="selectedBlockId"
                :active-lang="selectedLang"
                :mobile-preview="mobilePreview"
                @select-block="selectBlock"
            />
            </div>

            <div class="project-editor__add-blocks">
                <div class="project-editor__actions">
                    <button v-for="opt in blockTypeOptions" :key="opt.type" type="button" class="project-editor__action" @click="addBlock(opt.type)">
                        Add {{ opt.label }}
                    </button>
                </div>
            </div>
        </div>

        <!-- Right column: block editor panel -->
        <aside class="project-editor__block-panel">
            <!-- Sort panel -->
            <div v-if="showSort" class="project-editor__panel">
                <div class="project-editor__block-editor-header">
                    <span class="project-editor__label">Reorder blocks</span>
                    <button type="button" class="project-editor__ghost" @click="showSort = false">✕ Close</button>
                </div>
                <div class="project-editor__block-list">
                    <template v-for="(block, index) in project.contentBlocks" :key="block.id">
                        <div
                            draggable="true"
                            class="project-editor__block-item"
                            :class="{
                                'project-editor__block-item--active': block.id === selectedBlockId,
                                'project-editor__block-item--dragging': block.id === dragSrcId,
                                'project-editor__block-item--over': block.id === dragOverId,
                                'project-editor__block-item--hidden': block.hidden,
                            }"
                            @click="selectBlock(block.id); showSort = false; scrollToBlock(block.id)"
                            @mouseenter="scrollToBlock(block.id)"
                            @dragstart="onDragStart($event, block.id)"
                            @dragover="onDragOver($event, block.id)"
                            @dragleave="onDragLeave"
                            @drop="onDrop($event, block.id)"
                            @dragend="onDragEnd"
                        >
                            <button
                                type="button"
                                class="project-editor__visibility-btn"
                                :class="{ 'project-editor__visibility-btn--hidden': block.hidden }"
                                :title="block.hidden ? 'Section hidden — click to show' : 'Section visible — click to hide'"
                                @click.stop="block.hidden = !block.hidden"
                            >
                                <!-- Eye open -->
                                <svg v-if="!block.hidden" xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
                                <!-- Eye off -->
                                <svg v-else xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
                            </button>
                            <span class="project-editor__drag-handle" title="Drag to reorder">☰</span>
                            <span class="project-editor__block-item-body">
                                <span class="pe-block-num">{{ index + 1 }}</span>
                                <span class="pe-block-layout" v-html="LAYOUT_ICONS[block.type] || block.type" :title="block.type === 'TwoColumns' ? 'Two Columns' : 'Full Width'"></span>
                                <span class="pe-block-name" :class="{ 'pe-block-name--hidden': block.hidden }">{{ block.name || `Section ${index + 1}` }}</span>
                                <span class="pe-block-slots">
                                    <template v-if="block.type === 'TwoColumns'">
                                        <span v-html="SLOT_ICONS[block.left?.type] || block.left?.type || '?'" :title="block.left?.type"></span>
                                        <span class="pe-slot-sep">/</span>
                                        <span v-html="SLOT_ICONS[block.right?.type] || block.right?.type || '?'" :title="block.right?.type"></span>
                                    </template>
                                    <template v-else-if="block.type === 'FullWidth'">
                                        <span v-html="SLOT_ICONS[block.slot?.type] || block.slot?.type || '?'" :title="block.slot?.type"></span>
                                    </template>
                                </span>
                            </span>
                        </div>
                    </template>
                </div>
            </div>

            <!-- Settings panel: publish status + thumbnail + categories -->
            <div v-else-if="showProjectSettings" class="project-editor__panel pe-settings-panel">
                <div class="project-editor__block-editor-header">
                    <span class="project-editor__label">Settings</span>
                    <button type="button" class="project-editor__ghost" @click="showProjectSettings = false">✕ Close</button>
                </div>

                <input v-if="props.categories.length" type="hidden" name="categories_present" value="1">

                <!-- Publish status -->
                <div class="pe-settings-card">
                    <div class="pe-settings-card__header">
                        <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
                        <span>Publish status</span>
                    </div>
                    <div class="pe-settings-card__body">
                        <div class="pe-active-row">
                            <div class="pe-active-row__info">
                                <span class="pe-active-row__label">Active</span>
                                <span class="pe-active-row__hint">Visible on the website when enabled</span>
                            </div>
                            <div class="custom-control custom-switch custom-switch-off-danger custom-switch-on-success">
                                <input
                                    type="checkbox"
                                    class="custom-control-input"
                                    id="pe-active-slider"
                                    v-model="isActive"
                                    :true-value="true"
                                    :false-value="false"
                                >
                                <label class="pointer custom-control-label" for="pe-active-slider"></label>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Thumbnail (catalog cover) -->
                <div class="pe-settings-card">
                    <div class="pe-settings-card__header">
                        <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                        <span>Thumbnail</span>
                    </div>
                    <div class="pe-settings-card__body">
                        <p class="pe-settings-hint">Displayed on the Work listing page. Choose either an uploaded image or a Bunny video.</p>
                        <div class="pe-field">
                            <span class="pe-field-label">Thumbnail type</span>
                            <select v-model="project.thumbnailMedia.type" class="form-control form-control-sm">
                                <option value="image">Image upload</option>
                                <option value="bunny">Bunny video</option>
                            </select>
                        </div>

                        <template v-if="project.thumbnailMedia.type === 'image'">
                            <div
                                class="pe-drop-zone"
                                :class="{ 'pe-drop-zone--over': coverDragOver, 'pe-drop-zone--filled': !!coverPreview }"
                                @dragover.prevent="coverDragOver = true"
                                @dragleave="coverDragOver = false"
                                @drop="onCoverDrop"
                                @click="coverInputRef.click()"
                            >
                                <img v-if="coverPreview" :src="coverPreview" class="pe-drop-zone__preview" alt="">
                                <div v-if="coverPreview" class="pe-drop-zone__overlay">
                                    <span>Drop or click to replace</span>
                                    <button type="button" class="pe-drop-zone__clear" @click="clearCover" title="Remove">✕</button>
                                </div>
                                <div v-else class="pe-drop-zone__empty">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                                    <span>Drop or click to upload</span>
                                </div>
                            </div>
                            <input ref="coverInputRef" type="file" name="picture_cover" accept="image/*" class="pe-drop-zone__input" @change="onCoverChange">
                        </template>

                        <template v-else>
                            <div class="pe-field">
                                <span class="pe-field-label">Bunny embed URL</span>
                                <input
                                    v-model="project.thumbnailMedia.url"
                                    type="url"
                                    class="form-control form-control-sm"
                                    placeholder="https://player.mediadelivery.net/embed/{libraryId}/{videoId}"
                                >
                            </div>
                            <p class="pe-settings-hint mb-0">Bunny thumbnails autoplay, loop, and stay muted on the Work page.</p>
                        </template>
                    </div>
                </div>

                <!-- Categories -->
                <div v-if="props.categories.length" class="pe-settings-card">
                    <div class="pe-settings-card__header">
                        <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
                        <span>Categories</span>
                    </div>
                    <div class="pe-settings-card__body">
                        <div class="project-editor__categories">
                            <label
                                v-for="cat in props.categories"
                                :key="cat.id"
                                class="project-editor__category"
                                :class="{ 'project-editor__category--active': categoryChecked[cat.id] }"
                            >
                                <input
                                    type="checkbox"
                                    :value="cat.id"
                                    :checked="categoryChecked[cat.id]"
                                    @change="categoriesTouched = true; categoryChecked[cat.id] = $event.target.checked"
                                >
                                <img v-if="cat.picture" :src="cat.picture" :alt="cat.title" class="project-editor__category-img">
                                <span v-else class="project-editor__category-icon">🌍</span>
                                <span>{{ cat.title }}</span>
                            </label>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Meta panel: SEO meta + social -->
            <div v-else-if="showSettings" class="project-editor__panel pe-settings-panel">
                <div class="project-editor__block-editor-header">
                    <span class="project-editor__label">Meta</span>
                    <button type="button" class="project-editor__ghost" @click="showSettings = false">✕ Close</button>
                </div>

                <!-- SEO card -->
                <div class="pe-settings-card">
                    <div class="pe-settings-card__header">
                        <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
                        <span>Search engine (SEO)</span>
                    </div>
                    <div class="pe-settings-card__body">
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>Page title{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                            </div>
                            <p class="pe-settings-hint">Shown in the browser tab. Falls back to Meta title if empty.</p>
                            <input v-model="currentTranslation.pageTitle" type="text" class="pe-meta-input">
                        </div>
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>Meta title{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                                <span class="pe-char-count" :class="{ 'pe-char-count--warn': (currentTranslation.metaTitle || '').length > 60 }">{{ (currentTranslation.metaTitle || '').length }}/60</span>
                            </div>
                            <input v-model="currentTranslation.metaTitle" type="text" class="pe-meta-input" placeholder="Shown in search engine results">
                        </div>
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>Meta description{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                                <span class="pe-char-count" :class="{ 'pe-char-count--warn': (currentTranslation.metaDescription || '').length > 160 }">{{ (currentTranslation.metaDescription || '').length }}/160</span>
                            </div>
                            <textarea v-model="currentTranslation.metaDescription" class="pe-meta-input pe-meta-textarea" rows="3" placeholder="Search engine snippet (150–160 chars)"></textarea>
                        </div>
                    </div>
                </div>

                <!-- Open Graph / Social card -->
                <div class="pe-settings-card">
                    <div class="pe-settings-card__header">
                        <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>
                        <span>Social sharing (Open Graph)</span>
                    </div>
                    <div class="pe-settings-card__body">
                        <p class="pe-settings-hint">Used by Facebook, LinkedIn, WhatsApp, and Twitter/X when this page is shared. Falls back to SEO fields if empty.</p>
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>OG title{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                            </div>
                            <input v-model="currentTranslation.ogTitle" type="text" class="pe-meta-input" placeholder="Defaults to Meta title">
                        </div>
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>OG description{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                            </div>
                            <textarea v-model="currentTranslation.ogDescription" class="pe-meta-input pe-meta-textarea" rows="3" placeholder="Defaults to Meta description"></textarea>
                        </div>
                        <div class="pe-meta-field">
                            <div class="pe-meta-field__label">
                                <span>OG image</span>
                            </div>
                            <p class="pe-settings-hint">Recommended 1200×630 px. Also used as Twitter/X card image.</p>
                            <div
                                class="pe-drop-zone"
                                :class="{ 'pe-drop-zone--over': ogDragOver, 'pe-drop-zone--filled': !!ogPreview }"
                                @dragover.prevent="ogDragOver = true"
                                @dragleave="ogDragOver = false"
                                @drop="onOgDrop"
                                @click="ogInputRef.click()"
                            >
                                <img v-if="ogPreview" :src="ogPreview" class="pe-drop-zone__preview" alt="">
                                <div v-if="ogPreview" class="pe-drop-zone__overlay">
                                    <span>Drop or click to replace</span>
                                    <button type="button" class="pe-drop-zone__clear" @click="clearOg" title="Remove">✕</button>
                                </div>
                                <div v-else class="pe-drop-zone__empty">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                                    <span>Drop or click to upload</span>
                                </div>
                            </div>
                            <input ref="ogInputRef" type="file" name="picture_catalog" accept="image/*" class="pe-drop-zone__input" @change="onOgChange">
                        </div>
                    </div>
                </div>
            </div>

            <!-- Hero / Header editor -->
            <div v-else-if="isHeroSelected" class="project-editor__panel">
                <div class="project-editor__block-editor-header">
                    <span class="project-editor__label">Hero / Header</span>
                </div>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4v16M18 4v16M6 12h12"/></svg> Headline{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                    <input v-model="currentTranslation.headline" type="text" class="form-control form-control-sm" title="Main title displayed in the hero section">
                </label>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="3" y2="6"/><line x1="17" y1="12" x2="3" y2="12"/></svg> Subline{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                    <input v-model="currentTranslation.subline" type="text" class="form-control form-control-sm" title="Secondary line below the headline">
                </label>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg> Hero media type</span>
                    <select v-model="project.heroMedia.type" class="form-control form-control-sm">
                        <option value="image">Image</option>
                        <option value="youtube">YouTube</option>
                        <option value="frameio">Frame.io</option>
                        <option value="bunny">Bunny (mediadelivery.net)</option>
                        <option value="video">Video file</option>
                    </select>
                </label>

                <template v-if="project.heroMedia.type === 'image'">
                    <span class="project-editor__field-label pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> Hero image</span>
                    <ImageDropZone
                        :model-value="project.heroMedia.url"
                        :upload-url="uploadUrl"
                        @update:model-value="project.heroMedia.url = $event"
                    />
                </template>
                <label v-else>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg> Hero media URL</span>
                    <input v-model="project.heroMedia.url" type="url" class="form-control form-control-sm" placeholder="https://..." title="URL to the hero image, video, or embed">
                </label>
                <div v-if="project.heroMedia.type === 'bunny'" class="project-editor__checkboxes">
                    <label class="project-editor__checkbox">
                        <input type="checkbox" v-model="project.heroMedia.autoplay"> Autoplay
                    </label>
                    <label class="project-editor__checkbox">
                        <input type="checkbox" v-model="project.heroMedia.loop"> Loop
                    </label>
                    <label class="project-editor__checkbox">
                        <input type="checkbox" v-model="project.heroMedia.muted"> Muted
                    </label>
                </div>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> Client name{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                    <input v-model="currentTranslation.clientName" type="text" class="form-control form-control-sm" title="Company or client this project was made for">
                </label>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg> Year</span>
                    <input v-model="currentTranslation.year" type="number" class="form-control form-control-sm" title="Year the project was completed">
                </label>

                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> Awarded lines</span>
                    <textarea v-model="awardedText" class="form-control form-control-sm" rows="4" title="One award per line (e.g. Cannes Lions 2024)"></textarea>
                </label>

                <span class="project-editor__field-label pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg> Description{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                <RichTextEditor
                    :model-value="currentTranslation.description || ''"
                    @update:model-value="currentTranslation.description = $event"
                />

            </div>

            <!-- Dynamic block editor -->
            <div v-else-if="selectedBlock && !showSort && !showProjectSettings" class="project-editor__panel">
                <div class="project-editor__block-editor-header">
                    <span class="project-editor__label">{{ selectedBlock.name || `Block ${selectedBlockIndex + 1}` }} — {{ selectedBlock.type }}</span>
                    <button type="button" class="project-editor__danger" @click="removeSelectedBlock">Remove</button>
                </div>
                <label>
                    <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg> Block name</span>
                    <input v-model="selectedBlock.name" type="text" class="form-control form-control-sm" placeholder="Block name (optional)" title="Optional label shown in the sort list">
                </label>

                <!-- FullWidth editor -->
                <template v-if="selectedBlock.type === 'FullWidth'">
                    <div class="pe-type-picker">
                        <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock.slot.type === 'text' }" @click="selectedBlock.slot.type = 'text'" title="Text">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>
                            Text
                        </button>
                        <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock.slot.type === 'image' }" @click="selectedBlock.slot.type = 'image'" title="Image">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                            Image
                        </button>
                        <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock.slot.type === 'video' }" @click="selectedBlock.slot.type = 'video'" title="Video">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
                            Video
                        </button>
                    </div>

                    <template v-if="selectedBlock.slot.type === 'text'">
                        <RichTextEditor
                            :model-value="selectedBlock.slot.content[selectedLang] || ''"
                            @update:model-value="selectedBlock.slot.content[selectedLang] = $event"
                        />
                    </template>

                    <template v-else-if="selectedBlock.slot.type === 'image'">
                        <span class="project-editor__field-label pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> Image</span>
                        <ImageDropZone
                            :model-value="selectedBlock.slot.image.url"
                            :upload-url="uploadUrl"
                            @update:model-value="selectedBlock.slot.image.url = $event"
                        />
                        <label>
                            <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg> Alt text{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                            <input
                                :value="selectedBlock.slot.image.alt[selectedLang] || ''"
                                type="text"
                                class="form-control form-control-sm"
                                title="Describe the image for screen readers and SEO"
                                @input="selectedBlock.slot.image.alt[selectedLang] = $event.target.value"
                            >
                        </label>
                    </template>

                    <template v-else-if="selectedBlock.slot.type === 'video'">
                        <label>
                            <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg> Video provider</span>
                            <select v-model="selectedBlock.slot.media.type" class="form-control form-control-sm">
                                <option value="youtube">YouTube</option>
                                <option value="frameio">Frame.io</option>
                                <option value="bunny">Bunny (mediadelivery.net)</option>
                                <option value="video">Video file</option>
                            </select>
                        </label>
                        <label>
                            <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
                                <span v-if="selectedBlock.slot.media.type === 'youtube'">YouTube URL</span>
                                <span v-else-if="selectedBlock.slot.media.type === 'frameio'">Frame.io review link</span>
                                <span v-else-if="selectedBlock.slot.media.type === 'bunny'">Bunny embed URL</span>
                                <span v-else>Video URL</span>
                            </span>
                            <input v-model="selectedBlock.slot.media.url" type="url" class="form-control form-control-sm"
                                :placeholder="selectedBlock.slot.media.type === 'frameio' ? 'https://app.frame.io/reviews/...' : (selectedBlock.slot.media.type === 'bunny' ? 'https://player.mediadelivery.net/embed/{libraryId}/{videoId}' : 'https://...')">
                        </label>
                        <div v-if="selectedBlock.slot.media.type === 'bunny'" class="project-editor__checkboxes">
                            <label class="project-editor__checkbox">
                                <input type="checkbox" v-model="selectedBlock.slot.media.autoplay"> Autoplay
                            </label>
                            <label class="project-editor__checkbox">
                                <input type="checkbox" v-model="selectedBlock.slot.media.loop"> Loop
                            </label>
                            <label class="project-editor__checkbox">
                                <input type="checkbox" v-model="selectedBlock.slot.media.muted"> Muted
                            </label>
                        </div>
                        <template v-if="selectedBlock.slot.media.type !== 'frameio'">
                            <span class="project-editor__field-label pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> Poster image (optional)</span>
                            <ImageDropZone
                                :model-value="selectedBlock.slot.media.poster"
                                :upload-url="uploadUrl"
                                label="Optional"
                                @update:model-value="selectedBlock.slot.media.poster = $event"
                            />
                        </template>
                    </template>
                </template>

                <!-- TwoColumns editor -->
                <template v-else-if="selectedBlock.type === 'TwoColumns'">
                    <template v-for="colKey in ['left', 'right']" :key="colKey">
                        <span class="project-editor__field-label project-editor__settings-section">{{ colKey === 'left' ? 'Left' : 'Right' }} column</span>
                        <div class="pe-type-picker">
                            <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock[colKey].type === 'text' }" @click="selectedBlock[colKey].type = 'text'" title="Text">
                                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>
                                Text
                            </button>
                            <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock[colKey].type === 'image' }" @click="selectedBlock[colKey].type = 'image'" title="Image">
                                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                                Image
                            </button>
                            <button type="button" class="pe-type-btn" :class="{ 'pe-type-btn--active': selectedBlock[colKey].type === 'video' }" @click="selectedBlock[colKey].type = 'video'" title="Video">
                                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
                                Video
                            </button>
                        </div>

                        <template v-if="selectedBlock[colKey].type === 'text'">
                            <RichTextEditor
                                :model-value="selectedBlock[colKey].content[selectedLang] || ''"
                                @update:model-value="selectedBlock[colKey].content[selectedLang] = $event"
                            />
                        </template>

                        <template v-else-if="selectedBlock[colKey].type === 'image'">
                            <ImageDropZone
                                :model-value="selectedBlock[colKey].image.url"
                                :upload-url="uploadUrl"
                                :label="colKey === 'left' ? 'Left column' : 'Right column'"
                                @update:model-value="selectedBlock[colKey].image.url = $event"
                            />
                            <label>
                                <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg> Alt text{{ selectedLang ? ` (${selectedLang.toUpperCase()})` : '' }}</span>
                                <input
                                    :value="selectedBlock[colKey].image.alt[selectedLang] || ''"
                                    type="text"
                                    class="form-control form-control-sm"
                                    title="Describe the image for screen readers and SEO"
                                    @input="selectedBlock[colKey].image.alt[selectedLang] = $event.target.value"
                                >
                            </label>
                        </template>

                        <template v-else-if="selectedBlock[colKey].type === 'video'">
                            <label>
                                <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg> Video provider</span>
                                <select v-model="selectedBlock[colKey].media.type" class="form-control form-control-sm">
                                    <option value="youtube">YouTube</option>
                                    <option value="frameio">Frame.io</option>
                                    <option value="bunny">Bunny (mediadelivery.net)</option>
                                    <option value="video">Video file</option>
                                </select>
                            </label>
                            <label>
                                <span class="pe-field-label"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
                                    <span v-if="selectedBlock[colKey].media.type === 'youtube'">YouTube URL</span>
                                    <span v-else-if="selectedBlock[colKey].media.type === 'frameio'">Frame.io review link</span>
                                    <span v-else-if="selectedBlock[colKey].media.type === 'bunny'">Bunny embed URL</span>
                                    <span v-else>Video URL</span>
                                </span>
                                <input v-model="selectedBlock[colKey].media.url" type="url" class="form-control form-control-sm" :placeholder="selectedBlock[colKey].media.type === 'bunny' ? 'https://player.mediadelivery.net/embed/{libraryId}/{videoId}' : 'https://...'">
                            </label>
                            <div v-if="selectedBlock[colKey].media.type === 'bunny'" class="project-editor__checkboxes">
                                <label class="project-editor__checkbox">
                                    <input type="checkbox" v-model="selectedBlock[colKey].media.autoplay"> Autoplay
                                </label>
                                <label class="project-editor__checkbox">
                                    <input type="checkbox" v-model="selectedBlock[colKey].media.loop"> Loop
                                </label>
                                <label class="project-editor__checkbox">
                                    <input type="checkbox" v-model="selectedBlock[colKey].media.muted"> Muted
                                </label>
                            </div>
                        </template>
                    </template>
                </template>
            </div>
            <div v-else class="project-editor__block-panel-empty">
                <p>Select a block from the list to edit it.</p>
            </div>
        </aside>

    </div>
</template>

<style scoped>
.project-editor {
    display: grid;
    gap: 1.5rem;
    align-items: flex-start;
    grid-template-columns: 1fr 26rem;
}

.project-editor__controls {
    display: none;
}

.project-editor__upload-notice {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: .6rem;
    background: #fefce8;
    border: 1px solid #fde047;
    border-radius: .5rem;
    color: #713f12;
    font-size: .875rem;
    font-weight: 500;
    padding: .6rem 1rem;
}

.project-editor__upload-spinner {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border: 2px solid #fde047;
    border-top-color: #a16207;
    border-radius: 50%;
    animation: pe-spin .7s linear infinite;
    flex-shrink: 0;
}

@keyframes pe-spin {
    to { transform: rotate(360deg); }
}

/* .project-editor__controls is hidden (display:none set above) — only holds hidden inputs */

.project-editor__controls-sticky {
    align-content: start;
    display: grid;
    gap: 1rem;
    position: sticky;
    top: 5rem;
}

.project-editor__panel {
    background: #fff;
    border: 1px solid rgba(15, 23, 42, 0.08);
    border-radius: 1rem;
    display: grid;
    gap: 0.55rem;
    padding: 1rem;
}

.project-editor__panel label {
    color: #111827;
    display: grid;
    font-size: 0.82rem;
    font-weight: 600;
    gap: 0.2rem;
}

.project-editor__panel-header {
    align-items: start;
    display: flex;
    gap: 0.75rem;
    justify-content: space-between;
}

.project-editor__panel-header h3 {
    color: #0f172a;
    font-size: 1rem;
    margin: 0.15rem 0 0;
}

.project-editor__actions,
.project-editor__inline-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.project-editor__block-panel {
    align-content: start;
    display: grid;
    gap: 1rem;
    position: sticky;
    top: 5rem;
}

.project-editor__block-panel-empty {
    align-items: center;
    background: rgba(15, 23, 42, 0.02);
    border: 1px dashed rgba(15, 23, 42, 0.12);
    border-radius: 1rem;
    color: #94a3b8;
    display: flex;
    font-size: 0.85rem;
    justify-content: center;
    min-height: 8rem;
    padding: 1.5rem;
    text-align: center;
}

.project-editor__block-panel-empty p {
    margin: 0;
}

.project-editor__block-editor-header {
    align-items: center;
    display: flex;
    justify-content: space-between;
}

.project-editor__checkboxes {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
}

.project-editor__checkbox {
    align-items: center;
    cursor: pointer;
    display: flex !important;
    flex-direction: row !important;
    font-weight: 500 !important;
    gap: 0.4rem;
}

.project-editor__categories {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.project-editor__category {
    align-items: center !important;
    border: 1px solid rgba(15, 23, 42, 0.12);
    border-radius: 0.5rem;
    cursor: pointer;
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    font-size: 0.85rem;
    font-weight: 500;
    gap: 0.5rem;
    margin: 0;
    padding: 0.35rem 0.6rem;
    transition: border-color 0.15s, background 0.15s;
}

.project-editor__category input[type="checkbox"] {
    accent-color: #0f766e;
    cursor: pointer;
    flex-shrink: 0;
    height: 1rem;
    margin: 0;
    width: 1rem;
}

.project-editor__category--active {
    background: #f0fdf4;
    border-color: #0f766e;
}

.project-editor__category-img {
    border-radius: 0.3rem;
    flex-shrink: 0;
    height: 1.25rem;
    object-fit: cover;
    width: 1.25rem;
}

.project-editor__category-icon {
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 1;
}

/* ── Settings panel cards ─────────────────────────────────────────── */
.pe-settings-panel {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.pe-settings-card {
    border: 1px solid rgba(15, 23, 42, 0.1);
    border-radius: 0.85rem;
    overflow: hidden;
}

.pe-settings-card__header {
    align-items: center;
    background: rgba(15, 23, 42, 0.03);
    border-bottom: 1px solid rgba(15, 23, 42, 0.08);
    color: #475569;
    display: flex;
    font-size: 0.72rem;
    font-weight: 700;
    gap: 0.4rem;
    letter-spacing: 0.05em;
    padding: 0.55rem 0.85rem;
    text-transform: uppercase;
}

.pe-settings-card__body {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    padding: 0.85rem;
}

.pe-settings-hint {
    color: #64748b;
    font-size: 0.75rem;
    line-height: 1.5;
    margin: 0;
}

.pe-active-row {
    align-items: center;
    display: flex;
    gap: 0.75rem;
    justify-content: space-between;
}

.pe-active-row__info {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.pe-active-row__label {
    font-size: 0.85rem;
    font-weight: 600;
}

.pe-active-row__hint {
    color: #64748b;
    font-size: 0.72rem;
}

/* ── Meta panel fields ────────────────────────────────────────────── */
.pe-meta-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.pe-meta-field__label {
    align-items: baseline;
    display: flex;
    font-size: 0.75rem;
    font-weight: 600;
    gap: 0.5rem;
    justify-content: space-between;
}

.pe-char-count {
    color: #94a3b8;
    font-size: 0.68rem;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pe-char-count--warn {
    color: #ef4444;
    font-weight: 600;
}

.pe-meta-input {
    background: #fff;
    border: 1px solid rgba(15, 23, 42, 0.15);
    border-radius: 0.45rem;
    color: #0f172a;
    font-size: 0.82rem;
    line-height: 1.4;
    padding: 0.4rem 0.6rem;
    transition: border-color 0.15s, box-shadow 0.15s;
    width: 100%;
}

.pe-meta-input:focus {
    border-color: rgba(14, 116, 144, 0.5);
    box-shadow: 0 0 0 3px rgba(14, 116, 144, 0.12);
    outline: none;
}

.pe-meta-textarea {
    resize: vertical;
}

.project-editor__action,
.project-editor__ghost,
.project-editor__danger {
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    font-size: 0.82rem;
    font-weight: 700;
    padding: 0.55rem 0.9rem;
}

.project-editor__action,
.project-editor__ghost {
    background: #eff6ff;
    color: #1d4ed8;
}

.project-editor__danger {
    background: #fee2e2;
    color: #b91c1c;
}

.project-editor__block-list {
    display: grid;
    gap: 0.5rem;
}

.project-editor__block-item {
    align-items: center;
    background: #f8fafc;
    border: 1px solid transparent;
    border-radius: 0.9rem;
    color: #0f172a;
    cursor: pointer;
    display: grid;
    gap: 0 0.4rem;
    grid-template-columns: auto 1.4rem 1fr;
    padding: 0.55rem 0.95rem;
    text-align: left;
    transition: background 0.12s, border-color 0.12s, opacity 0.12s;
    user-select: none;
}

.project-editor__block-item-body {
    align-items: center;
    display: flex;
    gap: 0.35rem;
    min-width: 0;
}

.pe-block-num {
    color: #94a3b8;
    font-size: 0.72rem;
    font-weight: 700;
    min-width: 1.2rem;
}

.pe-block-layout {
    align-items: center;
    color: #475569;
    display: flex;
    flex-shrink: 0;
}

.pe-block-name {
    color: #0f172a;
    font-size: 0.82rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pe-block-name--hidden {
    background: #fee2e2;
    border-radius: 0.25rem;
    color: #b91c1c;
    padding: 0.05em 0.35em;
}

.pe-block-slots {
    align-items: center;
    color: #94a3b8;
    display: flex;
    flex-shrink: 0;
    gap: 0.15rem;
    margin-left: auto;
}

.pe-block-slots span {
    align-items: center;
    display: flex;
}

.pe-slot-sep {
    font-size: 0.65rem;
    line-height: 1;
}

.project-editor__drag-handle {
    align-self: center;
    color: #94a3b8;
    cursor: grab;
    font-size: 0.85rem;
    line-height: 1;
}

.project-editor__visibility-btn {
    align-items: center;
    background: none;
    border: none;
    border-radius: 0.35rem;
    color: #94a3b8;
    cursor: pointer;
    display: flex;
    flex-shrink: 0;
    line-height: 1;
    padding: 0.15rem;
    transition: color 0.15s;
}

.project-editor__visibility-btn:hover {
    color: #475569;
}

.project-editor__visibility-btn--hidden {
    color: #ef4444;
}

.project-editor__visibility-btn--hidden:hover {
    color: #b91c1c;
}

.project-editor__drag-handle:active {
    cursor: grabbing;
}

.project-editor__block-item--active {
    background: #ecfeff;
    border-color: rgba(14, 116, 144, 0.25);
}

.project-editor__block-item:not(.project-editor__block-item--active):hover {
    background: #f1f5f9;
    border-color: rgba(15, 23, 42, 0.12);
}

.project-editor__block-item--dragging {
    opacity: 0.4;
}

.project-editor__block-item--over {
    background: #f0f9ff;
    border-color: rgba(14, 116, 144, 0.5);
    border-style: dashed;
}

.project-editor__block-item small,
.project-editor__hint {
    color: #64748b;
}

.project-editor__preview {
    background: linear-gradient(180deg, rgba(248, 250, 252, 0.96), rgba(241, 245, 249, 0.96));
    border: 1px solid rgba(15, 23, 42, 0.08);
    border-radius: 1rem;
    display: grid;
    flex: 1 1 0;
    gap: 1rem;
    min-width: 320px;
    overflow: clip;
    padding: 1rem;
    transition: max-width 0.3s ease;
}

.project-editor__preview--mobile {
    flex: 0 0 auto;
    max-width: 390px;
    min-width: 320px;
    width: 390px;
}

.project-editor__renderer-wrap {
    width: 100%;
}

.project-editor__renderer-wrap--mobile {
    max-width: 390px;
    margin-left: auto;
    margin-right: auto;
    transition: max-width 0.3s ease;
}

.project-editor__preview-blocks {
    background: #fff;
    border-bottom: 1px solid rgba(15, 23, 42, 0.08);
    display: grid;
    gap: 0.75rem;
    margin: -1rem -1rem 0;
    padding: 0.9rem 1rem;
    position: sticky;
    top: 3.5rem;
    z-index: 10;
}

.project-editor__preview-blocks h3 {
    font-size: 1.05rem;
    font-weight: 600;
    margin: 0;
}

.project-editor__preview-blocks__bottom {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: space-between;
}

.project-editor__toolbar-actions {
    display: flex;
    gap: 0.4rem;
    margin-left: auto;
}

.project-editor__add-blocks {
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(6px);
    border-top: 1px solid rgba(15, 23, 42, 0.08);
    bottom: 0;
    margin: 0 -1rem -1rem;
    padding: 0.75rem 1rem;
    position: sticky;
    z-index: 10;
}

.project-editor__lang-tabs {
    display: flex;
    gap: 0.25rem;
}

.project-editor__sort-btn {
    align-items: center;
    background: rgba(15, 23, 42, 0.06);
    border: none;
    border-radius: 0.5rem;
    color: #475569;
    cursor: pointer;
    display: flex;
    font-size: 0.78rem;
    font-weight: 700;
    gap: 0.35rem;
    padding: 0.3rem 0.65rem;
    transition: background 0.12s, color 0.12s;
}

.project-editor__sort-btn:hover {
    background: rgba(15, 23, 42, 0.11);
    color: #0f172a;
}

.project-editor__sort-btn--active {
    background: #0f172a;
    color: #fff;
}

.project-editor__lang-tabs--preview {
    align-items: center;
    gap: 0.35rem;
}

.project-editor__lang-label {
    color: #64748b;
    font-size: 0.78rem;
}

.project-editor__lang-tab {
    background: rgba(15, 23, 42, 0.06);
    border: none;
    border-radius: 0.3rem;
    color: #475569;
    cursor: pointer;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 0.2rem 0.55rem;
}

.project-editor__lang-tab--active {
    background: #0f172a;
    color: #fff;
}

.project-editor__json {
    font-family: Consolas, Monaco, monospace;
    font-size: 0.82rem;
}

.project-editor__resize-handle {
    align-items: center;
    background: rgba(15, 23, 42, 0.06);
    border-radius: 0.35rem;
    color: #64748b;
    cursor: col-resize;
    display: flex;
    font-size: 1rem;
    justify-content: center;
    padding: 0.15rem 0.4rem;
    user-select: none;
    transition: background 0.12s, color 0.12s;
}

.project-editor__resize-handle:hover {
    background: rgba(15, 23, 42, 0.12);
    color: #0f172a;
}

.project-editor__preview--resizing {
    cursor: col-resize;
    user-select: none;
}

.project-editor__field-label {
    color: #374151;
    font-size: 0.85rem;
    font-weight: 600;
}

.project-editor__settings-section {
    border-top: 1px solid rgba(15, 23, 42, 0.08);
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    padding-top: 0.5rem;
    text-transform: uppercase;
}

.pe-field-label {
    align-items: center;
    display: flex;
    gap: 0.3rem;
}

.pe-field-label svg {
    color: #94a3b8;
    flex-shrink: 0;
}

.pe-type-picker {
    background: #f1f5f9;
    border-radius: 0.75rem;
    display: flex;
    gap: 0.2rem;
    padding: 0.2rem;
}

.pe-type-btn {
    align-items: center;
    background: transparent;
    border: none;
    border-radius: 0.55rem;
    color: #64748b;
    cursor: pointer;
    display: flex;
    flex: 1;
    font-size: 0.78rem;
    font-weight: 600;
    gap: 0.3rem;
    justify-content: center;
    padding: 0.4rem 0.5rem;
    transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}

.pe-type-btn:hover:not(.pe-type-btn--active) {
    background: rgba(255, 255, 255, 0.7);
    color: #0f172a;
}

.pe-type-btn--active {
    background: #fff;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
    color: #0f172a;
}

.project-editor__col-divider {
    border-top: 1px solid rgba(15, 23, 42, 0.08);
    margin-top: 0.25rem;
    padding-top: 0.75rem;
}

@media (max-width: 1200px) {
    .project-editor {
        grid-template-columns: 1fr 22rem;
    }
}

@media (max-width: 900px) {
    .project-editor {
        grid-template-columns: 1fr;
    }

    .project-editor__block-panel {
        position: static;
    }
}

/* ── Picture upload drop zones (Meta sidebar) ─────────────────────── */
.pe-picture-field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.pe-drop-zone__input {
    display: none;
}

.pe-drop-zone {
    border: 2px dashed rgba(15, 23, 42, 0.18);
    border-radius: 0.65rem;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    transition: border-color 0.15s, background 0.15s;
    user-select: none;
}

.pe-drop-zone--over {
    background: #f0f9ff;
    border-color: rgba(14, 116, 144, 0.55);
}

.pe-drop-zone--filled {
    border-style: solid;
    border-color: rgba(15, 23, 42, 0.12);
}

.pe-drop-zone__empty {
    align-items: center;
    color: #94a3b8;
    display: flex;
    flex-direction: column;
    font-size: 0.72rem;
    gap: 0.4rem;
    justify-content: center;
    min-height: 5rem;
    padding: 1rem;
}

.pe-drop-zone__preview {
    display: block;
    height: auto;
    max-height: 9rem;
    object-fit: cover;
    width: 100%;
}

.pe-drop-zone__overlay {
    align-items: center;
    background: rgba(15, 23, 42, 0.45);
    bottom: 0;
    color: #fff;
    display: flex;
    font-size: 0.72rem;
    gap: 0.5rem;
    justify-content: center;
    left: 0;
    opacity: 0;
    padding: 0.35rem 0.5rem;
    position: absolute;
    right: 0;
    top: 0;
    transition: opacity 0.15s;
}

.pe-drop-zone:hover .pe-drop-zone__overlay,
.pe-drop-zone--over .pe-drop-zone__overlay {
    opacity: 1;
}

.pe-drop-zone__clear {
    background: rgba(255, 255, 255, 0.2);
    border: none;
    border-radius: 50%;
    color: #fff;
    cursor: pointer;
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.2rem 0.35rem;
    transition: background 0.15s;
}

.pe-drop-zone__clear:hover {
    background: rgba(239, 68, 68, 0.75);
}
</style>