/* MonkeyCams — Editor: panel lateral, modales, etiquetas, modo edición */

/* Cabecera del inventario. Con la clase has-editor-session en <html>
   (session-class.js la pone desde el <head>, updateEditBtn la mantiene):

     sin sesión  →  llave (abre el modal de login), y nada más
     con sesión  →  lápiz (modo edición)   +   menú de cuenta (⋮)

   Añadir cámara y guardar cambios ya no viven aquí: se fueron a la barra
   inferior del modo edición (ver .editor-actions-bar más abajo).

   El display:none por defecto es la guarda primaria contra el destello
   inicial; el estilo inline de #editor-edit-btn lo refuerza por si el HTML
   viene de una caché vieja del service worker. */
#editor-edit-btn {
    display: none;
}
.has-editor-session #editor-edit-btn {
    display: flex;
}
.has-editor-session #editor-settings-btn {
    display: none;
}

/* El menú ⋮ requiere sesión entero: dentro solo hay exportar la colección y
   cerrar sesión, y las dos son acciones de dueño (ver app-menu.js). Sin
   sesión no queda nada que enseñar, así que se oculta el contenedor. */
#editor-account-wrap {
    display: none;
}
.has-editor-session #editor-account-wrap {
    display: block;
}

/* Rótulo de grupo dentro del menú, no interactivo. */
.ac-menu-heading {
    padding: 7px 11px 4px;
    margin: 0;
    text-align: left;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-faint);
}

/* El email deja de ser la cabecera del menú y pasa a ser su pie: encima ya
   están las acciones de exportar. Se le da el borde por arriba. */
.editor-account-email {
    border-top: 1px solid var(--border-subtle);
    margin-top: 4px;
}

/* Menú de cuenta. Hereda de .lb-detail-actions-dropdown (el ⋮ del lightbox),
   pero aquel se diseñó para flotar sobre una foto a pantalla completa: usa los
   grises de overlay, que sobre el negro de la app se leen como un panel
   apagado y lavado. Aquí se reasienta sobre los tokens de superficie de la
   app, con el mismo lenguaje que los modales del editor. */
.editor-account-menu {
    /* .lb-detail-actions-dropdown trae z-index: 30, pensado para el lightbox.
       Aquí compite con la píldora de guardar (50) en el mismo contexto de
       apilado y perdía. Ver --z-account-menu en tokens.css. */
    z-index: var(--z-account-menu);
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    min-width: 216px;
    padding: 5px;
    box-shadow:
        0 12px 32px rgba(var(--ac-overlay-black), 0.6),
        0 2px 6px rgba(var(--ac-overlay-black), 0.4);
}

/* Email de la cuenta, como cabecera no interactiva. Desde que el modal de
   ajustes pasó a ser solo de login, no se veía en ninguna parte con qué
   cuenta estabas. Dos líneas al estilo de los ajustes de iOS: el rótulo
   pequeño dice qué es, el email va en el color de texto principal. */
.editor-account-email {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    /* .inventory-hero centra su texto y esto lo heredaba: el email salía
       centrado dentro del menú. */
    text-align: left;
    gap: 1px;
    padding: 8px 11px 10px;
    font-size: 0.74rem;
    color: var(--text-main);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 240px;
}
.editor-account-email::before {
    content: "Sesión iniciada";
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-faint);
}
.editor-account-email:empty {
    display: none;
}

/* El item destructivo iba a 0.70 de opacidad sobre un rojo ya de por sí
   suave (--err-tx, #ff8579): quedaba desvaído y no leía como «cuidado».
   Ahora usa el rojo del sistema a plena intensidad, que es lo que hace Apple
   en sus menús contextuales, y va emparejado con su glifo. */
.editor-account-menu .ac-btn-menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 11px;
    border-radius: 8px;
    font-size: 0.78rem;
}
.editor-account-menu .ac-btn-menu-item--danger {
    color: var(--err-color);
}
.editor-account-menu .ac-btn-menu-item svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}
@media (hover: hover) {
    .editor-account-menu .ac-btn-menu-item--danger:hover {
        background: rgba(var(--err-rgb), 0.14);
        color: var(--err-color);
    }
}

/* ── Editor ──────────────────────────────────────────────────────────────── */
/* Pending change indicator — outline en <tr> no respeta border-radius del grupo */
tr.editor-pending > td {
    background: rgba(var(--accent-rgb), 0.07);
}
tr.editor-pending > td:first-child {
    box-shadow: inset 3px 0 0 var(--accent);
}
.cam-card.editor-pending {
    border-color: rgba(var(--accent-rgb), 0.45);
    box-shadow: inset 0 0 0 1.5px rgba(var(--accent-rgb), 0.45);
}

/* Edit mode: cursor + indicador sutil (misma lógica que la vista compacta)
   — borde tintado en tarjetas, franja izquierda en tabla; sin outline
   rectangular que en la tabla se lee demasiado fuerte. */
body.edit-mode #tableBody tr[data-serial],
body.edit-mode #groupedTableContainer tr[data-serial] {
    cursor: pointer;
    outline: none;
}

body.edit-mode #tableBody tr[data-serial] > td:first-child,
body.edit-mode #groupedTableContainer tr[data-serial] > td:first-child {
    box-shadow: inset 3px 0 0 rgba(var(--accent-rgb), 0.32);
}

body.edit-mode .brand-panel .cam-card[data-camera-id] {
    cursor: pointer;
    outline: none;
    border-color: rgba(var(--accent-rgb), 0.32);
    transition:
        transform 0.18s var(--ease-out),
        box-shadow 0.18s var(--ease-out),
        border-color 0.15s var(--ease-out);
}

@media (hover: hover) {
    body.edit-mode #tableBody tr[data-serial]:hover > td,
    body.edit-mode #groupedTableContainer tr[data-serial]:hover > td {
        background: rgba(var(--accent-rgb), 0.04);
    }

    body.edit-mode #tableBody tr[data-serial]:hover > td:first-child,
    body.edit-mode #groupedTableContainer tr[data-serial]:hover > td:first-child {
        box-shadow: inset 3px 0 0 rgba(var(--accent-rgb), 0.55);
    }

    body.edit-mode .brand-panel .cam-card[data-camera-id]:hover {
        border-color: rgba(var(--accent-rgb), 0.55);
        box-shadow: var(--shadow-md);
        transform: translateX(3px);
    }
}

/* Edit panel (slide-in) */
#editor-panel {
    position: fixed;
    top: 0;
    right: 0;
    height: 100vh;
    height: 100dvh;
    width: min(380px, 100vw);
    /* Mismo gris que .editor-modal (bg-surface), explícito en cabecera/cuerpo */
    background: var(--bg-surface);
    border-left: 1px solid var(--border);
    box-shadow: -8px 0 32px rgba(0, 0, 0, 0.4);
    z-index: var(--z-overlay);
    overflow: hidden;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
}

@media (prefers-reduced-motion: no-preference) {
    #editor-panel {
        animation: epSlideIn 0.2s ease-out;
    }
    @keyframes epSlideIn {
        from {
            transform: translateX(100%);
            opacity: 0;
        }
        to {
            transform: translateX(0);
            opacity: 1;
        }
    }
}

.ep-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 18px 16px 14px;
    border-bottom: 1px solid var(--border);
    background: var(--bg-surface);
}

.ep-title {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ep-brand {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
}

.ep-model {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text-main);
}

.ep-serial {
    font-family: "DM Mono", monospace;
    font-size: 0.72rem;
    color: var(--text-faint);
}

.ep-scroll {
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Reserva siempre el hueco de la barra de scroll (aunque no haga
       falta) — sin esto, el contenido se desplazaba unos px al abrir o
       cerrar el catálogo de etiquetas, según si aparecía o desaparecía la
       barra. Progresivo: navegadores sin soporte simplemente no reservan
       el hueco, mismo comportamiento que antes. */
    scrollbar-gutter: stable;
    display: flex;
    flex-direction: column;
    /* Solo tiene efecto con VirtualKeyboard API activa (ver editor.js) —
       0px sin soporte. Deja hueco al final del scroll para que se pueda
       bajar hasta ver "Aplicar cambios"/"Cancelar" por encima del teclado
       en vez de que quede tapado por él. */
    padding-bottom: env(keyboard-inset-height, 0px);
}

.ep-form {
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    /* Con poco contenido (catálogo de etiquetas cerrado), crece para ocupar
       el hueco sobrante de .ep-scroll y empuja las acciones al fondo real
       del panel — sin esto se quedaban justo debajo del formulario, con un
       hueco vacío hasta el borde. Con contenido suficiente para necesitar
       scroll no cambia nada: flex-grow no tiene espacio extra que repartir
       y el tamaño lo sigue marcando el propio contenido. */
    flex: 1 0 auto;
}

.ep-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.ep-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.ep-select,
.ep-input,
.ep-textarea {
    background: var(--bg-body);
    border: 1px solid var(--border);
    color: var(--text-main);
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    font-size: 0.875rem;
    font-family: inherit;
    width: 100%;
    outline: none;

    transition:
        border-color 0.15s,
        box-shadow 0.15s;
}
.ep-textarea {
    resize: vertical;
}

.ep-select:focus,
.ep-input:focus,
.ep-textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-dim);
}

.ep-actions {
    display: flex;
    gap: 10px;
    flex-shrink: 0;
    padding: 12px 16px max(12px, env(safe-area-inset-bottom));
    border-top: 1px solid var(--border);
    background: var(--bg-surface);
}
.ep-actions .btn {
    flex: 1;
}

@media (max-width: 768px) {
    #editor-panel {
        width: 100%;
        max-width: 100%;
    }

    .ep-actions .btn {
        min-height: 44px;
    }
}

#editor-review-save-btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Settings modal */
.editor-modal-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 100vh;
    height: 100dvh;
    background: rgba(0, 0, 0, 0.6);
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Solo tiene efecto con VirtualKeyboard API activa (ver editor.js) — 0px
       sin soporte. Encoge el área de centrado por debajo del teclado: con
       align-items:center de arriba, el modal queda centrado en el hueco
       realmente visible sin necesitar JS (watchVisualViewport se
       desactiva a propósito en ese caso, ver editor.js). */
    padding-bottom: calc(16px + env(keyboard-inset-height, 0px));
}

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

.editor-modal {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 24px;
    width: min(440px, 100%);
    max-height: calc(100% - 32px);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}

.editor-modal-title {
    font-size: 1rem;
    font-weight: 700;
}

.editor-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--bg-surface);
}

.editor-modal-header .editor-modal-title {
    margin: 0;
    flex: 1;
    min-width: 0;
}

.editor-modal-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 4px 0;
}

.editor-modal-subtitle {
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text-main);
}

.editor-pin-status {
    display: block;
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: -6px;
}

/* El anillo de foco del campo (outline 3px + outline-offset 3px = 6px
   fuera del borde) dejaba solo ~2px libres hasta este texto con el mismo
   -6px que .editor-pin-status — en móvil se veía solapado. Sin negativo:
   el hueco del gap del modal (14px) ya deja sitio de sobra al anillo. */
.editor-pin-error {
    font-size: 0.8rem;
    color: var(--err-color, #ff453a);
}

.editor-modal-desc {
    font-size: 0.84rem;
    color: var(--text-muted);
    line-height: 1.55;
}

.editor-modal-desc a {
    color: var(--accent);
    text-decoration: underline;
}

.editor-modal-desc code {
    font-family: "DM Mono", monospace;
    font-size: 0.82em;
    background: var(--bg-hover);
    padding: 1px 4px;
    border-radius: 3px;
}

.editor-modal-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.editor-modal-input {
    background: var(--bg-body);
    border: 1px solid var(--border);
    color: var(--text-main);
    border-radius: var(--radius-sm);
    padding: 8px 12px;
    min-height: 44px; /* control principal del modal: mínimo táctil */
    font:
        0.875rem "DM Mono",
        monospace;
    width: 100%;
    outline: none;
    transition:
        border-color 0.15s,
        box-shadow 0.15s;
}

.editor-modal-input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-dim);
}

/* Estos modales enfocan el input al abrir (correcto: son de teclear), pero
   el foco por script en un campo de texto siempre pinta :focus-visible, y
   el anillo amarillo global chocaba con el borde acento del propio campo
   (doble anillo, parecía un fallo). Se armoniza al acento: sigue habiendo
   indicador de foco de 3px, solo cambia el color. Gana al global de
   components.css porque aquel usa :where() (especificidad cero). */
.editor-modal-input:focus-visible {
    outline-color: var(--accent) !important;
}

/* El <form> del login es un hijo directo más de .editor-modal, así que hereda
   su reparto: sin esto, sus campos quedaban pegados entre sí (4px en vez de
   14px), porque un <form> display:block agrupa a todos sus hijos en un único
   elemento flex y el `gap` del modal deja de separarlos. */
#editor-login-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* Estado cerrado del modal de login. `inert` es la única fuente de verdad:
   el navegador se encarga de sacarlo del foco, del tab y del árbol de
   accesibilidad, y esta regla lo oculta a la vista.

   No se usa `hidden` (ni display:none) a propósito: los gestores de
   contraseñas descartan los campos que no están renderizados cuando recorren
   la página, y este login vive en un modal que arranca cerrado — con
   `hidden` no lo veían nunca. Con opacity el elemento sigue teniendo caja
   real y los campos siguen siendo detectables. pointer-events:none evita que
   este backdrop a pantalla completa se coma los clics del inventario. */
/* Ver los tokens --z-modal-* en tokens.css: el orden entre diálogos se
   declara ahí, no se deja al orden en el DOM. */
#editor-settings-modal {
    z-index: var(--z-modal-login);
}
#ac-global-confirm {
    z-index: var(--z-modal-confirm);
}
#editor-settings-modal[inert] {
    opacity: 0;
    pointer-events: none;
}

.editor-modal-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* ── Panel de revisión de cambios pendientes ─────────────────────────────── */
.editor-review-list {
    display: flex;
    flex-direction: column;
    max-height: 40vh;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.editor-review-item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    cursor: pointer;
}
.editor-review-item:not(:last-child) {
    border-bottom: 1px solid var(--border-subtle);
}
.editor-review-item input[type="checkbox"] {
    margin-top: 2px;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    accent-color: var(--accent);
}
.editor-review-item-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    font-size: 0.86rem;
}
.editor-review-item-main strong {
    font-weight: 600;
    color: var(--text-main);
}
.editor-review-item-sub {
    font-size: 0.76rem;
    color: var(--text-muted);
}
@media (hover: hover) {
    .editor-review-item:hover {
        background: var(--bg-hover);
    }
}

/* Compact modal when keyboard is open on mobile — toggled via JS (.modal-compact)
   using visualViewport.height (o, con VirtualKeyboard API, el evento
   geometrychange — ver editor.js), ya que @media (max-height) usa la layout
   viewport, que no cambia con el teclado virtual.
   Sin align-items:flex-start aquí a propósito: con VirtualKeyboard API el
   centrado por flexbox (align-items:center, regla base de arriba) debe
   seguir activo sin ayuda de JS; el camino sin esa API ya fuerza
   flex-start desde JS (centerModalInViewport, incondicional mientras el
   modal esté abierto) antes de calcular el marginTop a mano, así que
   repetirlo aquí era redundante. */
.modal-compact {
    padding: 8px !important;
    /* Conserva el hueco del teclado (0px sin VirtualKeyboard API) — la
       forma corta `padding` de arriba lo pisaría sin esto, al llevar
       también !important. */
    padding-bottom: calc(8px + env(keyboard-inset-height, 0px)) !important;
}

.modal-compact .editor-modal {
    padding: 16px !important;
    gap: 8px !important;
}

/* Toast */
.editor-toast {
    position: fixed;
    bottom: calc(80px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--z-editor-toast);
    background: var(--bg-raised);
    border: 1px solid var(--border);
    color: var(--text-main);
    padding: 10px 20px;
    border-radius: 8px;
    font:
        500 14px system-ui,
        sans-serif;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    white-space: normal;
    max-width: min(480px, calc(100vw - 32px));
    width: max-content;
    text-align: center;
    word-break: break-word;
}

.editor-toast-error {
    border-color: var(--err-color);
    color: var(--err-tx);
}

/* Camera rows marked for deletion */
tr.editor-deleted {
    opacity: 0.3;
    pointer-events: none;
    text-decoration: line-through;
}

@media (prefers-reduced-motion: no-preference) {
    .editor-toast {
        animation: toastIn 0.2s ease-out;
    }
    @keyframes toastIn {
        from {
            opacity: 0;
            transform: translateX(-50%) translateY(8px);
        }
        to {
            opacity: 1;
            transform: translateX(-50%) translateY(0);
        }
    }
}

/* ============================================
   ETIQUETAS — panel de edición
============================================ */
.ep-tags-field {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.ep-tags-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.ep-tags-head .ep-label {
    margin: 0;
}

.ep-tags-assigned-empty,
.ep-tags-catalog-empty {
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-faint);
    line-height: 1.45;
}

.ep-tag-assigned-chips,
.ep-tag-catalog-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}

.ep-tags-catalog {
    box-sizing: border-box;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    background: rgba(var(--ac-overlay-white), 0.04);
    overflow: hidden;
}

.ep-tags-catalog-summary {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    width: 100%;
    min-height: 44px;
    padding: 0 14px;
    margin: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    cursor: pointer;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    line-height: 1.2;
    list-style: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.12s ease, background 0.12s ease;
}

.ep-tags-catalog-summary::-webkit-details-marker {
    display: none;
}

.ep-tags-catalog-summary::after {
    content: "";
    flex-shrink: 0;
    width: 7px;
    height: 7px;
    margin-left: auto;
    border-right: 1.5px solid var(--text-faint);
    border-bottom: 1.5px solid var(--text-faint);
    transform: rotate(45deg) translateY(-1px);
    transition: transform 0.15s var(--ease-out);
}

.ep-tags-catalog[open] .ep-tags-catalog-summary::after {
    transform: rotate(-135deg) translateY(1px);
}

@media (hover: hover) {
    .ep-tags-catalog-summary:hover {
        background: rgba(var(--ac-overlay-white), 0.04);
        color: var(--text-main);
    }
}

.ep-tags-catalog-summary:focus {
    outline: none;
}

.ep-tags-catalog-summary:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent);
}

.ep-tags-catalog[open] .ep-tags-catalog-summary {
    border-bottom: 1px solid var(--border-subtle);
}

.ep-tags-catalog[open] .ep-tags-search {
    display: block;
    width: auto;
    margin: 10px 12px 8px;
}

.ep-tags-catalog[open] .ep-tag-catalog-chips {
    padding: 0 12px 4px;
}

.ep-tags-catalog[open] .ep-tags-catalog-empty {
    padding: 0 12px 10px;
}

/* Chip de etiqueta = .ac-pill con .ac-pill--neutral / --accent (ver el
   marcado en renderTagSection). Reimplementaba el componente entero con los
   MISMOS valores —fondo 0.07, hover 0.13, foco, píldora accent al activarse—
   y ya solo queda aquí lo que de verdad difiere: su tamaño. Ninguno de los
   cinco de .ac-pill--* encaja (--s es 0.68rem, se queda corto para leer
   nombres de etiqueta; --l es 0.85rem y desborda el panel), así que el
   tamaño es propio a propósito, no por olvido. */
.ep-tag-chip {
    padding: 4px 11px;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.4;
    transition:
        background 0.12s ease,
        color 0.12s ease;
}

.ep-new-tag-row {
    display: flex;
    gap: 8px;
    align-items: center;
}

.ep-new-tag-row[hidden] {
    display: none !important;
}

.ep-new-tag-input {
    flex: 1;
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg-input, var(--bg-surface));
    color: var(--text-main);
    font: inherit;
    font-size: 0.8rem;
}

.ep-new-tag-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-dim);
}

/* Confirmar = ac-icon-btn--success; cancelar/quitar/borrar = ac-icon-btn--subtle
   (ver components.css); añadir = ac-icon-btn--accent */

/* ── Tag item wrapper (chip + action) ── */
.ep-tag-item {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.ep-tag-item--assigned {
    gap: 4px;
}

/* Etiqueta del catálogo que no usa ninguna cámara. Se marca con un punto
   discreto en vez de un color de aviso: no es un error, solo información
   para decidir si borrarla. El punto va en el ::after del contenedor y no
   del chip para no descolocar el texto ni el botón de borrar. */
.ep-tag-item--unused .ep-tag-chip {
    opacity: 0.6;
}
.ep-tag-item--unused::after {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--text-faint);
    flex-shrink: 0;
    margin-left: -1px;
}

/* Matiz único de ep-tag-unassign: al llegar por teclado no se pone rojo
   como el resto de tonos --subtle, solo aclara el icono a --text-muted
   (sigue pudiendo quitar la etiqueta sin que parezca ya destructivo). */
.ep-tag-unassign:focus-visible {
    color: var(--text-muted);
}

/* ep-tag-del (cancelar nueva etiqueta) es el único que además se revela al
   pasar el ratón por toda la fila, no solo sobre el propio botón —
   deliberadamente discreto porque puede haber muchas etiquetas por
   pantalla. */
@media (hover: hover) {
    .ep-tag-item:hover .ep-tag-del {
        opacity: 1;
    }
}

/* ── Añadir cámara (junto a las herramientas del listado) ───────────────── */
/* Sin `hidden`: .icon-btn pone display:flex como regla de autor y ganaría al
   [hidden]{display:none} del user-agent por origen. Toda la visibilidad en
   CSS, además, hace que los cuatro caminos que salen del modo edición no
   tengan que acordarse de este botón. */
#editor-new-btn {
    display: none;
}
.has-editor-session body.edit-mode #editor-new-btn {
    display: flex;
}

/* .controls-right está oculto en móvil (solo lleva el conmutador de vistas,
   que allí no aplica). En modo edición vuelve, pero únicamente con el botón
   de añadir dentro. */
@media (max-width: 768px) {
    .has-editor-session body.edit-mode .controls-right {
        display: flex;
    }
    .has-editor-session body.edit-mode .controls-right .btn-group-views {
        display: none;
    }
}

/* Con un botón más, la fila de controles se pasaba de largo a 1280px y el
   grupo de la derecha caía a una segunda línea. El buscador cede ese hueco
   (queda por encima de 180px, de sobra para el placeholder entero). Por
   debajo de ~1250px la fila se parte igualmente, como ya hacía antes de este
   botón: es un contenedor con wrap y ese es su comportamiento normal. */
@media (min-width: 769px) {
    body.edit-mode .search-box {
        min-width: 180px;
    }
}

/* ── Guardar cambios (píldora flotante del modo edición) ────────────────── */
/* Por qué flota: el inventario mide ~3000px en móvil y la cabecera es
   estática, así que editando una cámara del final el botón quedaba a ~750px
   por encima del pulgar.
   Por qué es una píldora suelta y no una barra a todo lo ancho: es una sola
   acción, y ocupando el ancho entero pesaba más de lo que vale.
   Y por qué aparece y desaparece: siendo una sola, no hay nada a lo que
   descolocar al irse — que era el motivo de dejarla fija cuando eran dos. */
.editor-actions-bar {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    /* Por encima del sidenav (30) y por debajo del scrim del cajón móvil
       (60): al abrir el cajón la píldora queda atenuada detrás, no encima. */
    z-index: var(--z-actions-bar);
    display: none;
}

/* En julio una barra flotante inferior TAPÓ el botón «Aplicar cambios» del
   panel de edición y ese fue uno de los motivos de retirarla. Aquel intento
   compensaba su altura con ResizeObserver + padding, y esa maquinaria fue la
   causa raíz; aquí basta con quitarla de en medio mientras haya algo por
   encima (`.editor-overlay-open`, ver lockBodyScroll en editor.js). */
.has-editor-session
    body.edit-mode.editor-has-pending:not(.editor-overlay-open)
    .editor-actions-bar {
    display: flex;
}

.editor-actions-bar-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-height: 40px;
    padding: 0 16px;
    border-radius: var(--radius-pill);
    font-size: 0.78rem;
    font-weight: 600;
    /* Se apoya sobre el listado, no sobre un fondo propio: la sombra es lo
       único que la separa de las tarjetas que pasan por debajo. */
    box-shadow:
        0 6px 20px rgba(var(--ac-overlay-black), 0.5),
        0 1px 3px rgba(var(--ac-overlay-black), 0.4);
}
.editor-actions-bar-btn svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}

/* La última cámara del listado tiene que quedar por encima de la píldora:
   sin esto se quedaba debajo y no había forma de abrirla. Solo cuando la
   píldora está de verdad en pantalla. */
body.edit-mode.editor-has-pending .app-layout {
    padding-bottom: 72px;
}

@media (prefers-reduced-motion: no-preference) {
    .has-editor-session
        body.edit-mode.editor-has-pending:not(.editor-overlay-open)
        .editor-actions-bar {
        animation: editorBarIn 0.22s var(--ease-out);
    }
    @keyframes editorBarIn {
        from {
            opacity: 0;
            transform: translateY(8px);
        }
    }
}

@media (min-width: 1081px) {
    /* En escritorio se aleja un poco del borde, al ritmo del resto del
       layout. No se centra: el centro de la ventana no es el centro del
       contenido (a la izquierda está el sidenav) y quedaba descuadrada. */
    .editor-actions-bar {
        right: 28px;
        bottom: 28px;
    }
}

/* ============================================
   CAMPO DE FOTO (panel de edición)
============================================ */
.ep-photo-preview {
    width: 100%;
    margin-top: 8px; /* cuelga de la cabecera de arriba */
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-raised);
    border: 1px solid var(--border-subtle);
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Sin foto no se pinta el hueco: el panel de un móvil de 844px de alto ya
   iba justo (817 de contenido en 748 de área visible), y un recuadro vacío
   de 72px empujaba «Aplicar cambios» fuera de pantalla sin aportar nada que
   no diga ya el botón «Añadir foto». */
.ep-photo-preview.is-empty {
    display: none;
}
.ep-photo-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* Mientras sube, la vista previa local se atenúa: es la única señal de que
   lo que se ve todavía no está en el servidor. */
.ep-photo-preview.is-uploading img {
    opacity: 0.55;
}
.ep-photo-empty {
    font-size: 0.76rem;
    color: var(--text-faint);
}
/* Misma cabecera que «Etiquetas» (.ep-tags-head) y «Carretes»
   (.cam-sectit--action): rótulo a la izquierda, acción a la derecha. */
.ep-photo-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.ep-photo-head .ep-label {
    margin-bottom: 0;
}
.ep-photo-actions {
    display: flex;
    gap: 14px;
    align-items: center;
}
/* El <label> hace de botón y el <input type=file> real se esconde dentro:
   los navegadores no dejan estilar el control nativo, y su aspecto por
   defecto desentona con todo lo demás del panel. */
.ep-photo-pick {
    cursor: pointer;
}
.ep-photo-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
/* El foco del teclado llega al input escondido, no al label: sin esto,
   tabular hasta «Añadir foto» no se ve por ninguna parte.
   `:has(:focus-visible)` y no `:focus-within`: lo segundo también acierta
   cuando el foco viene de un clic, así que al pulsar «Añadir foto» el borde
   azul se quedaba puesto encima —el diálogo de archivos devuelve el foco al
   input— hasta tocar otra cosa. `:focus-visible` es justo la distinción que
   hace el navegador entre foco por teclado (hay que enseñarlo) y foco por
   puntero (no hace falta: ya sabes dónde has pulsado). */
.ep-photo-pick:has(:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.ep-photo-status {
    margin: 6px 0 0;
    font-size: 0.72rem;
    color: var(--text-muted);
}
/* Sin mensaje no ocupa: reservar la línea siempre son 14px de más en un
   panel que en móvil ya no cabe entero. */
.ep-photo-status:empty {
    display: none;
}
.ep-photo-status.is-error {
    color: var(--err-tx);
}

/* ============================================
   FORMULARIO DE CARRETE
============================================ */
.ac-roll-modal {
    max-width: 460px;
    width: 100%;
}
.ac-roll-form-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.ac-roll-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
@media (max-width: 420px) {
    .ac-roll-row {
        grid-template-columns: 1fr;
    }
}
.ac-roll-modal .ep-field {
    margin: 0;
}
/* La película no se puede cambiar al descargar: es el mismo carrete. */
.ac-roll-modal input[readonly] {
    opacity: 0.7;
    cursor: default;
}

/* ISO bloqueado por la película elegida: se lee, no se teclea. Mismo
   tratamiento que el «Con carrete» del panel cuando lo decide el carrete. */
.ac-roll-modal .ep-input[readonly],
.ac-roll-modal .ep-select:disabled {
    opacity: 0.7;
    cursor: default;
}
.ac-roll-iso-note {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
}
.ac-roll-iso-note[hidden] {
    display: none;
}
.ac-roll-iso-note-text {
    min-width: 0;
}

/* ── Ficha de la película elegida (catálogo, films.json) ─────────────────
   Debajo del desplegable: para qué sirve y con qué luz. El desplegable dice
   CUÁL es; esto dice si es la que toca hoy, que es la pregunta real. */
.ac-roll-film-select + .ep-input {
    margin-top: 8px;
}
.ac-roll-film-info {
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: var(--bg-raised);
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.ac-roll-film-info[hidden] {
    display: none;
}
.ac-roll-film-tech {
    margin: 0;
    font-family: "DM Mono", monospace;
    font-size: 0.7rem;
    color: var(--text-faint);
}
.ac-roll-film-light {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}
.ac-roll-film-when {
    margin: 0;
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--text-main);
    text-wrap: pretty;
}
/* «Para qué es ideal», en píldoras — mismo trato que `.cams-badges--uses` en
   Cámaras. Antes era una frase suelta, sin estilo propio. */
.ac-roll-film-uses {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}
/* «Antes de dispararla», destacado — mismo trato que `.cams-card-watch` en
   Cámaras (barra de aviso a la izquierda): antes vivía detrás de un
   `<details>`, y en la tarjeta del catálogo detrás de DOS (el acordeón de la
   tarjeta y este). El usuario pidió el 2026-08-07 que se leyera en cuanto se
   abre la ficha, sin un segundo clic. */
.ac-roll-film-tips {
    margin: 0;
    padding-left: 10px;
    border-left: 2px solid var(--border);
}
.ac-roll-film-tips-k {
    display: block;
    font-size: 0.68rem;
    font-weight: 600;
    color: var(--text-main);
    margin-bottom: 2px;
}
.ac-roll-film-tips-v {
    margin: 0;
    font-size: 0.76rem;
    line-height: 1.45;
    color: var(--text-muted);
    text-wrap: pretty;
}

/* ============================================
   CARRETES DENTRO DEL PANEL DE EDICIÓN
   Reutiliza el marcado de la ficha (rolls.js), así que hereda su aspecto de
   `assets/css/inventory.css`. Aquí solo se ajusta lo que cambia por vivir
   dentro de un formulario en vez de en la ficha.
============================================ */
.ep-rolls-field {
    /* El primer elemento de la sección es su propio título, así que no hace
       falta el `.ep-label` que llevan los demás campos. */
    padding-top: 4px;
    border-top: 1px solid var(--border-subtle);
}
.ep-rolls-field .cam-sectit {
    margin-top: 10px;
}
/* Dentro del panel, la ficha de carrete no necesita el fondo de tarjeta: ya
   está sobre una superficie elevada y quedaría una caja dentro de otra. */
.ep-rolls-field .cam-field--roll {
    background: none;
    border: 1px dashed var(--border-subtle);
}

/* Nota bajo un campo: explica una restricción sin gritar. */
.ep-field-note {
    margin: 5px 0 0;
    font-size: 0.7rem;
    line-height: 1.4;
    color: var(--text-faint);
}
.ep-rolls-note,
.ep-services-note {
    margin-top: 10px;
}

/* Un select bloqueado tiene que LEERSE como bloqueado, no como roto: se
   conserva el color del texto (el valor sigue siendo un dato que se consulta)
   y se quita el aire de control pulsable. */
.ep-select:disabled {
    opacity: 1;
    color: var(--text-muted);
    background: var(--bg-raised);
    border-style: dashed;
    cursor: default;
}
