/* Manifest Edit */

@layer base, components, utilities;

/* Self-contained: every rule the plugin needs lives here, so this stylesheet works
   on its own. Authors override without specificity battles — rules are :where()
   wrapped and keyed off data-edit-* attributes, including the injected affordances
   (handles, overlay, live region, toolbar, menu). No class names to collide with. */

@layer utilities {

    /* ---- Editable area (armed) ----
       Chrome is opt-in. Most uses of this plugin are a resize handle or a sortable
       list, which should look like themselves; only .authoring gets the outline and
       the region label. */
    :where([data-edit-armed]) {
        position: relative;
    }

    /* Quiet until touched. A page covered in dashed boxes reads as a diagram of
       itself; the affordance only has to be there when you go looking for it. */
    :where([data-edit-armed][data-edit-authoring]) {
        outline: 1px dashed transparent;
        outline-offset: 6px;
        border-radius: var(--radius);
        transition: outline-color 0.12s ease;
    }

    :where([data-edit-armed][data-edit-authoring]):hover,
    :where([data-edit-armed][data-edit-authoring]):focus-within {
        outline-color: var(--color-line);
    }

    :where([data-edit-armed][data-edit-authoring])::before {
        content: attr(data-edit-label);
        position: absolute;
        inset-block-start: -1.5rem;
        inset-inline-start: 0;
        font-size: 0.7rem;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--color-content-subtle);
        pointer-events: none;
        opacity: 0;
        transition: opacity 0.12s ease;
    }

    :where([data-edit-armed][data-edit-authoring]):hover::before,
    :where([data-edit-armed][data-edit-authoring]):focus-within::before {
        opacity: 1;
    }

    /* ---- Reorder (pointer + keyboard; touch-action:none lets touch-drag beat scroll) ---- */
    :where([data-edit-sortable]) {
        cursor: grab;
        touch-action: none;
        transition: opacity 0.12s ease, outline-color 0.12s ease;
    }

    :where([data-edit-sortable]):hover,
    :where([data-edit-sortable]):focus-within {
        outline: 1px solid var(--edit-accent, var(--color-brand-content));
        outline-offset: 3px;
    }

    :where([data-edit-sortable], [data-edit-movable]):focus-visible {
        outline: 2px solid var(--edit-accent, var(--color-brand-content));
        outline-offset: 3px;
    }

    /* Lifted out of the flow and following the pointer. */
    :where([data-edit-sortable][data-edit-dragging]) {
        z-index: 1000;
        cursor: grabbing;
        box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
    }

    /* The stand-in holding the slot the drop would land in — a translucent copy of
       the element by default, because the clearest preview of where it lands is the
       thing itself. Restyle it freely: hide its contents for an empty outlined slot,
       give it a background, animate it. */
    :where([data-edit-ghost]) {
        opacity: var(--edit-ghost-opacity, 0.4);
        pointer-events: none;
    }

    /* Nothing else should react while a drag is in progress */
    :where([data-edit-dragging-in]) {
        cursor: grabbing;
        user-select: none;

        & :where([data-edit-sortable]:not([data-edit-dragging])) {
            cursor: grabbing;
        }
    }

    :where([data-edit-grabbed]) {
        outline: 2px dashed var(--edit-accent, var(--color-brand-content));
        outline-offset: 3px;
    }

    /* ---- Move (positioned children) ---- */
    :where([data-edit-movable]) {
        cursor: move;
        touch-action: none;
    }

    :where([data-edit-movable]):hover {
        outline: 1px solid var(--edit-accent, var(--color-brand-content));
        outline-offset: 2px;
    }

    /* ---- Inline text ---- */
    :where([data-edit-armed]) [contenteditable="true"] {
        outline: 1px solid transparent;
        outline-offset: 2px;
        border-radius: 3px;
        transition: outline-color 0.12s ease;
    }

    :where([data-edit-armed]) [contenteditable="true"]:hover {
        outline-color: color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 45%, transparent);
    }

    :where([data-edit-armed]) [contenteditable="true"]:focus {
        outline: 2px solid var(--edit-accent, var(--color-brand-content));
    }

    /* ---- Size handles ----
       Injected as siblings of the element's own markup, so its native :hover and
       :focus still fire and its body stays interactive. */
    :where([data-edit-sizable]) {
        position: relative;
    }

    /* Handles reveal on approach rather than sitting on the element permanently */
    :where([data-edit-sizable]) :where([data-edit-handle])::before {
        opacity: 0;
        transition: opacity 0.12s ease, background-color 0.15s ease;
    }

    :where([data-edit-sizable]):hover :where([data-edit-handle])::before,
    :where([data-edit-sizable]):focus-within :where([data-edit-handle])::before {
        opacity: 1;
    }

    :where([data-edit-handle]) {
        position: absolute;
        z-index: 100;
        background: transparent;
        --h: var(--edit-size-handle, 1rem);

        /* Hairline, revealed on hover */
        &::before {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 1px;
            height: 1px;
            background: transparent;
            transition: background-color 0.15s ease;
            pointer-events: none;
        }

        &:hover::before,
        &:active::before {
            background-color: var(--edit-accent, var(--color-brand-content));
        }
    }

    :where([data-edit-handle]):focus-visible {
        outline: 2px solid var(--edit-accent, var(--color-brand-content));
    }

    /* Edges span their axis; corners are square. A corner value contains a hyphen. */
    :where([data-edit-handle="top"], [data-edit-handle="bottom"]) {
        left: 0;
        width: 100%;
        height: var(--h);
        cursor: ns-resize;

        &::before {
            width: 100%;
        }
    }

    :where([data-edit-handle="left"], [data-edit-handle="right"], [data-edit-handle="start"], [data-edit-handle="end"]) {
        top: 0;
        width: var(--h);
        height: 100%;
        cursor: ew-resize;

        &::before {
            height: 100%;
        }
    }

    :where([data-edit-handle*="-"]) {
        width: var(--h);
        height: var(--h);
    }

    /* Inset — each handle straddles its edge; a corner matches one rule per axis.
       inset-inline-* carries the logical start/end values, so they flip for RTL. */
    :where([data-edit-handle^="top"]) {
        top: calc(var(--h) * -0.5);
    }

    :where([data-edit-handle^="bottom"]) {
        bottom: calc(var(--h) * -0.5);
    }

    :where([data-edit-handle$="left"]) {
        left: calc(var(--h) * -0.5);
    }

    :where([data-edit-handle$="right"]) {
        right: calc(var(--h) * -0.5);
    }

    :where([data-edit-handle$="start"]) {
        inset-inline-start: calc(var(--h) * -0.5);
    }

    :where([data-edit-handle$="end"]) {
        inset-inline-end: calc(var(--h) * -0.5);
    }

    /* Corner cursors; the logical pair flips with direction. */
    :where([data-edit-handle="top-left"], [data-edit-handle="bottom-right"], [data-edit-handle="top-start"], [data-edit-handle="bottom-end"]) {
        cursor: nwse-resize;
    }

    :where([data-edit-handle="top-right"], [data-edit-handle="bottom-left"], [data-edit-handle="top-end"], [data-edit-handle="bottom-start"]) {
        cursor: nesw-resize;
    }

    [dir=rtl] :where([data-edit-handle="top-start"], [data-edit-handle="bottom-end"]) {
        cursor: nesw-resize;
    }

    [dir=rtl] :where([data-edit-handle="top-end"], [data-edit-handle="bottom-start"]) {
        cursor: nwse-resize;
    }

    /* Collapsed past --edit-size-collapse-* — authors restyle freely */
    :where([data-edit-collapsed]) {
        opacity: 0.45;
    }

    /* Full-viewport capture layer during a size or move drag */
    :where([data-edit-overlay]) {
        position: fixed;
        inset: 0;
        z-index: 9999;
        background: transparent;
    }

    /* Screen-reader announcements (keyboard grab / move / drop) */
    :where([data-edit-live]) {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    @media (prefers-reduced-motion: reduce) {

        :where([data-edit-armed]) > [draggable="true"],
        :where([data-edit-handle])::before {
            transition: none;
        }
    }
}

/* ---- Authoring chrome (toolbar + class/scope menu) ---- */
@layer components {

    /* Presence is script's business — it knows which route is on screen. Whether it
       is seen is not, so the toolbar is styled and revealed here. */
    :where([data-edit-toolbar]) {
        display: none;
        position: fixed;
        inset-block-end: 1rem;
        inset-inline-end: 1rem;
        z-index: 9999;
        gap: 0.5rem;
        align-items: center;

        & button[disabled] {
            opacity: 0.35;
            pointer-events: none;
        }
    }

    :root[data-edit-active] :where([data-edit-toolbar]) {
        display: flex;
    }

    /* A popover: the top layer sits above every stacking context, so no handle,
       overlay or z-index anywhere on the page can paint over it. */
    :where([data-edit-menu]) {
        position: fixed;
        margin: 0;
        width: 16rem;
        padding: 0.6rem;
        display: flex;
        flex-direction: column;
        gap: 0.4rem;
        background: var(--color-surface-1);
        border: 1px solid var(--color-line);
        border-radius: var(--radius);
        box-shadow: 0 8px 30px rgb(0 0 0 / 0.2);

        & input {
            width: 100%;
            font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
            font-size: 0.75rem;
        }

        & small {
            font-size: 0.7rem;
            text-transform: uppercase;
            letter-spacing: 0.05em;
            color: var(--color-content-subtle);
        }
    }
}
