/* FOSFENO :: Panel de control Tema verde acido y negro, con acentos en naranja neon. Movil: una columna. Pantalla ancha: dos columnas. */ @font-face { font-family: "Xirod"; src: url("/panel/fonts/xirod.otf") format("opentype"); font-display: swap; } :root { --bg: #060a06; --card: #0d120c; --line: #243016; --green: #b4ff00; /* verde acido */ --green-d: #86bd00; --orange: #ff7a00; /* naranja acido */ --orange-n: #ff9d2a; /* naranja neon */ --ink: #050705; /* negro: texto sobre superficies brillantes */ --txt: #cfe8ad; /* texto claro sobre fondo oscuro */ --dim: #6f8a52; --red: #ff3b2f; } * { box-sizing: border-box; margin: 0; padding: 0; } /* El atributo 'hidden' debe ocultar siempre, incluso sobre display:flex */ [hidden] { display: none !important; } body { background: var(--bg); color: var(--txt); font-family: "Segoe UI", Roboto, system-ui, sans-serif; -webkit-tap-highlight-color: transparent; padding-bottom: 48px; } /* --- Barra superior fija: titulo + pestanas + avisos --- */ .topbar { position: sticky; top: 0; z-index: 10; background: var(--bg); } /* --- Cabecera con el titulo centrado y las pestanas a su derecha --- */ header { position: relative; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 10px 20px; padding: 14px 46px; border-bottom: 2px solid var(--green-d); background: var(--bg); } header h1 { font-family: "Xirod", "Arial Black", sans-serif; font-size: 32px; font-weight: 400; letter-spacing: 0.09em; color: var(--green); text-shadow: 0 0 18px rgba(180, 255, 0, 0.65); } #conn { position: absolute; right: 20px; top: 50%; transform: translateY(-50%); } /* --- Pestanas MOTORES / MAPPING --- */ .tabs { display: flex; gap: 8px; } .tab { position: relative; cursor: pointer; font-family: "Xirod", "Arial Black", sans-serif; font-size: 12px; font-weight: 400; letter-spacing: 0.07em; padding: 10px 15px; border-radius: 10px; background: #161d10; border: 2px solid var(--line); color: var(--dim); } .tab.active { border-color: var(--orange); color: var(--orange-n); box-shadow: 0 0 12px rgba(255, 122, 0, 0.35); } /* Punto verde en la pestana MAPPING cuando el mapping esta activado, para saber desde MOTORES que la salida se esta deformando. */ .tabdot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px var(--green); margin-left: 7px; vertical-align: middle; } /* En movil el titulo baja de tamano para que las pestanas quepan al lado */ @media (max-width: 560px) { header { padding: 12px 34px; gap: 8px 12px; } header h1 { font-size: 23px; } .tab { padding: 9px 11px; font-size: 11px; } #conn { right: 12px; } } .dot { width: 13px; height: 13px; border-radius: 50%; display: inline-block; } .dot.on { background: var(--green); box-shadow: 0 0 9px var(--green); } .dot.off { background: var(--red); box-shadow: 0 0 9px var(--red); } /* --- Disposicion: movil en una columna --- */ main { max-width: 560px; margin: 0 auto; padding: 16px; display: flex; flex-direction: column; gap: 14px; } .column { display: contents; } /* en movil, las columnas no existen */ /* Orden de las tarjetas cuando estan todas en una sola columna (movil). Toda tarjeta de
tiene que estar en esta lista: la que falte se queda en order 0 y se cuela LA PRIMERA, por mucho que en el HTML este abajo. Primero las pastillas (lo que se toca en directo) y justo despues el destino, que es su pareja: que lanzas / a donde va. */ #card-power { order: 1; } #card-engines { order: 2; } #card-destino { order: 3; } #card-audio { order: 4; } #card-sens { order: 5; } #ctl-butterchurn, #ctl-editor, #ctl-mixer, #ctl-projectm { order: 6; } #card-now { order: 7; } #card-sys { order: 8; } #net-foot { order: 9; } /* --- Disposicion: pantalla ancha (portatil) en dos columnas --- */ @media (min-width: 880px) { main { width: 94%; max-width: 1600px; flex-direction: row; align-items: flex-start; gap: 18px; } .column { display: flex; flex-direction: column; gap: 14px; flex: 1 1 0; } } /* --- Vistas (pestanas) --- MOTORES ensena todo menos las tarjetas de mapping, y al reves. Salvo la tarjeta de propiedades de capa, que MOTORES se lleva prestada cuando estas editando una capa (ver colocarPropiedades en panel.js). */ body[data-view="motores"] [data-vista="mapping"] { display: none !important; } body[data-view="motores"] #destino-props #card-propiedades { display: block !important; } body[data-view="mapping"] main > .column > :not([data-vista="mapping"]) { display: none !important; } body[data-view="mapping"] main { flex-direction: column; width: 100%; max-width: 900px; } body[data-view="mapping"] .column { display: contents; } /* En pantalla ancha el mapping se reparte: la previsualizacion grande a la izquierda (que es donde se trabaja) y las capas con sus propiedades a la derecha, sin tener que bajar y subir todo el rato. */ @media (min-width: 1000px) { body[data-view="mapping"] main { display: grid; width: 96%; max-width: 1700px; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); grid-template-areas: "previa capas" "previa props" "previa ."; align-items: start; align-content: start; gap: 16px; } body[data-view="mapping"] #card-mapping { grid-area: previa; } body[data-view="mapping"] #card-capas { grid-area: capas; } body[data-view="mapping"] #card-propiedades { grid-area: props; } /* La previsualizacion manda: que ocupe todo el alto util disponible */ body[data-view="mapping"] #map-preview { aspect-ratio: 16 / 9; } } /* --- Tarjetas --- */ .card { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 16px; display: flex; flex-direction: column; gap: 12px; } .card.center { align-items: center; } /* Cabecera de tarjeta: titulo centrado, boton de info a la derecha. El hueco lateral evita que un titulo largo se meta debajo del boton. */ .cardhead { position: relative; width: 100%; display: flex; align-items: center; justify-content: center; min-height: 30px; padding: 0 34px; } /* Titulo de cada tarjeta: mas grande y en la fuente Xirod */ .cardhead .label { font-family: "Xirod", "Arial Black", sans-serif; font-size: 16px; font-weight: 400; letter-spacing: 0.04em; } .label { color: var(--green); font-size: 13px; text-transform: uppercase; letter-spacing: 0.09em; font-weight: 700; } .value { color: var(--orange-n); font-weight: 800; } .hint { color: var(--dim); font-size: 12px; line-height: 1.45; } .row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; } .row .cmd { flex: 1; } /* En una fila de etiqueta + desplegable, el desplegable no baja de un ancho usable: si no cabe, la fila parte en dos lineas en vez de estrujarlo. */ .row .label { flex: 1 1 auto; } .row select.inline { flex: 0 1 auto; min-width: 148px; max-width: 100%; } /* --- Boton de informacion (circular naranja, esquina de la tarjeta) --- */ .info { position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 28px; height: 28px; border-radius: 50%; background: var(--orange); color: var(--ink); border: none; font-weight: 900; font-style: italic; font-size: 15px; cursor: pointer; box-shadow: 0 0 10px rgba(255, 122, 0, 0.5); } .info:active { background: var(--orange-n); } /* --- Boton de encendido (circular grande) --- */ .power-btn { width: 128px; height: 128px; border-radius: 50%; border: none; cursor: pointer; font-weight: 900; font-size: 26px; letter-spacing: 0.05em; background: var(--green); color: var(--ink); box-shadow: 0 0 26px rgba(180, 255, 0, 0.55); } .power-btn.off { background: var(--card); color: var(--dim); border: 3px solid var(--line); box-shadow: none; } /* --- Selector de motor (botones circulares) --- */ .engines { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; } .engine { width: 96px; aspect-ratio: 1 / 1; border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; cursor: pointer; background: var(--card); border: 3px solid var(--line); color: var(--txt); } /* En movil, algo mas pequenos para que entren TRES por fila: con 96 px se quedaban en un 2+2+1 descuadrado (flex parte la linea antes de encoger). */ @media (max-width: 560px) { .engines { gap: 10px; } .engine { width: 86px; } .engine strong { font-size: 12px; } } .engine strong { font-size: 13px; } .engine small { font-size: 9px; color: var(--dim); } .engine.active { background: var(--green); color: var(--ink); border-color: var(--orange); box-shadow: 0 0 20px rgba(180, 255, 0, 0.6); } .engine.active small { color: var(--ink); } /* En modo configurar, la pastilla abierta se marca distinto de la que esta sonando: naranja = "la estas editando", verde = "es la que se ve". */ .engine.editando { border-color: var(--orange); border-style: dashed; box-shadow: 0 0 16px rgba(255, 157, 42, 0.5); } .engine.nueva { border-style: dashed; color: var(--dim); } .engine.nueva strong { font-size: 22px; } /* --- Fila de destinos (salida / capas) --- Deliberadamente distintas de las pestanas de arriba: aquellas cambian de pantalla, estas eligen a donde va lo que dispares. */ .subtabs { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 4px; } .subtab { padding: 8px 14px; border-radius: 999px; cursor: pointer; background: #161d10; border: 2px solid var(--line); color: var(--dim); font-weight: 700; font-size: 12px; letter-spacing: 0.08em; max-width: 14ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .subtab.active { background: var(--orange); color: var(--ink); border-color: var(--orange); } .subtab.nueva { border-style: dashed; } #destino-props { margin-top: 12px; } /* Prestada de MAPPING: dentro de MOTORES no lleva su propio marco, que quedaria como una tarjeta dentro de otra */ #destino-props #card-propiedades { background: none; border: none; padding: 0; border-radius: 0; } .cmd.del { color: #ff8a7a; } /* --- Botones de comando --- */ .cmd, .sysbtn { padding: 13px; border-radius: 11px; cursor: pointer; background: #161d10; border: 1px solid var(--line); color: var(--txt); font-weight: 700; font-size: 14px; } .cmd:active, .sysbtn:active { background: #202a16; } .cmd.accent { background: var(--green); color: var(--ink); border: none; } /* --- Selectores y sliders --- */ select { width: 100%; padding: 12px; border-radius: 11px; background: #161d10; color: var(--txt); border: 1px solid var(--line); font-size: 14px; } select.inline { width: auto; padding: 8px 10px; } input[type=range] { width: 100%; accent-color: var(--green); height: 30px; } .check { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--txt); } .check input { width: 22px; height: 22px; accent-color: var(--orange); } /* --- Botones segmentados --- */ .seg { display: flex; gap: 6px; } .segbtn { flex: 1; padding: 11px 6px; border-radius: 10px; cursor: pointer; background: #161d10; border: 2px solid var(--line); color: var(--dim); font-weight: 700; font-size: 13px; } .segbtn.active { border-color: var(--orange); color: var(--orange-n); box-shadow: 0 0 12px rgba(255, 122, 0, 0.35); } /* --- BPM --- */ .bpm { font-size: 30px; font-weight: 900; color: var(--orange-n); text-shadow: 0 0 14px rgba(255, 157, 42, 0.6); font-variant-numeric: tabular-nums; } /* --- Sliders del mezclador --- */ .slider { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; } .slider .head { display: flex; justify-content: space-between; font-size: 13px; color: var(--dim); } .slider .head b { color: var(--green); font-weight: 800; } /* --- Editor CodeMirror --- */ .CodeMirror { height: 220px; border-radius: 11px; border: 1px solid var(--green-d); font-size: 13px; font-family: "Fira Mono", Consolas, monospace; } /* --- Tarjeta de estado --- */ #card-now { text-align: center; } .now { font-size: 15px; color: var(--orange-n); word-break: break-word; } /* --- Sistema --- */ .sys { flex-direction: row; } .sys .sysbtn { flex: 1; } .sysbtn.danger { color: var(--red); border-color: var(--red); } /* --- Pie con la direccion del panel --- */ .netfoot { text-align: center; color: var(--dim); font-size: 12px; font-family: monospace; padding: 4px 0 8px; } /* --- Banda de avisos (dentro de la barra superior fija) --- */ .notif { display: flex; align-items: center; gap: 10px; padding: 12px 16px; font-size: 14px; font-weight: 600; } .notif.lv-info { background: var(--green); color: var(--ink); } .notif.lv-warn { background: var(--orange); color: var(--ink); } .notif.lv-error { background: var(--red); color: #fff; } .notif span { flex: 1; } .notif button { background: transparent; border: none; color: inherit; font-size: 22px; font-weight: 900; cursor: pointer; line-height: 1; } /* --- Ventana de informacion --- */ .modal { position: fixed; inset: 0; z-index: 50; background: rgba(3, 6, 3, 0.88); display: flex; align-items: center; justify-content: center; padding: 20px; } .modal-box { background: var(--card); border: 2px solid var(--green); border-radius: 16px; padding: 22px; max-width: 460px; width: 100%; max-height: 80vh; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; box-shadow: 0 0 30px rgba(180, 255, 0, 0.3); } .modal-box h2 { font-family: "Xirod", "Arial Black", sans-serif; font-weight: 400; color: var(--green); font-size: 16px; letter-spacing: 0.06em; text-align: center; } .modal-box p { color: var(--txt); font-size: 14px; line-height: 1.5; } /* --- Bloques agrupados dentro de una tarjeta --- Un grupo de controles que aparece o desaparece junto (por ejemplo los de la camara o los del fondo Butter en el mezclador). */ .stack { display: flex; flex-direction: column; gap: 12px; } /* Controles que ahora mismo no pintan nada: siguen visibles pero apagados, asi se ve que existen sin que despisten. */ .dim { opacity: 0.42; } /* Resumen del mezclador: la linea que dice que va a salir por el proyector */ .hint.resumen { border-left: 3px solid var(--orange); padding: 6px 0 6px 10px; color: var(--txt); font-size: 13px; } /* --- Previsualizacion del mapping --- */ #map-preview { width: 100%; aspect-ratio: 16 / 9; display: block; margin: 6px 0; background: #0a0a0a; border: 1px solid var(--line); border-radius: 8px; touch-action: none; cursor: crosshair; } /* --- Lista de capas del mapping --- Una fila por capa: nombre + fuente a la izquierda, botones a la derecha. La fila entera selecciona; los botones no la seleccionan. */ #map-list { display: flex; flex-direction: column; gap: 8px; } .capa { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 9px 10px; border-radius: 11px; background: #161d10; border: 2px solid var(--line); } .capa.sel { border-color: var(--orange); box-shadow: 0 0 12px rgba(255,122,0,0.3); } .capa.oculta { opacity: 0.45; } .capa .txt { flex: 1; min-width: 0; } .capa .nom { display: block; color: var(--txt); font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .capa .src { display: block; color: var(--dim); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .capa.mascara .nom { color: #ff6b6b; } .capa button { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px; cursor: pointer; background: #0d120c; border: 1px solid var(--line); color: var(--txt); font-size: 14px; font-weight: 700; line-height: 1; padding: 0; } .capa button:disabled { opacity: 0.3; } .capa .del { color: var(--red); } /* Malla: los +/- son botones pequenos y van juntos, no barras a lo ancho */ .grupo { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; } #map-sub-dec, #map-sub-inc { flex: 0 0 auto; width: 46px; padding: 10px 0; font-size: 17px; } #map-sub-val { min-width: 40px; text-align: center; } /* Campo de texto (nombre de la capa) */ .txt[type="text"] { flex: 1; padding: 10px; border-radius: 10px; font-size: 14px; background: #161d10; color: var(--txt); border: 1px solid var(--line); } /* Favoritos de projectM: lista de visuales para pinchar en directo */ #pm-fav-list { display: flex; flex-direction: column; gap: 8px; max-height: 220px; overflow-y: auto; } #pm-fav-list .favplay { text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #pm-fav-list .favdel { flex: 0 0 auto; }