			:root{
				color-scheme: dark;
				/* ── dX Latam brand tokens (dx-design / Gudstudio 2025) ── */
				--dx-red:#B52C1F; --dx-black:#282D27; --dx-gray-dark:#565F5F;
				--dx-gray-mid:#888A8B; --dx-white:#FFFFFF; --dx-bg-light:#F0EFEB;
				--dx-font:'Blauer Nue','Outfit','Helvetica Neue',Helvetica,Arial,sans-serif;
				/* ── Semantic aliases (dark-first UI, derived from brand black) ── */
				--red:var(--dx-red);
				--red-soft:rgba(181,44,31,.14);
				--red-light:#d9685a;
				--green:#3FB873;
				--bg:var(--dx-black);
				--bg-sidebar:#20241f;
				--surface:#31362f;
				--surface-alt:#3b403a;
				--border:#3c4138;
				--text:var(--dx-bg-light);
				--text-muted:#a7a99f;
				--text-faint:var(--dx-gray-mid);
			}
			*{ box-sizing:border-box; }
			body{ font-family:var(--dx-font); font-weight:400; margin:0; background:var(--bg); color:var(--text); overflow-x:hidden; -webkit-font-smoothing:antialiased; }
			a{ color:inherit; text-decoration:none; }
			td a{ font-weight:700; border-bottom:1px solid transparent; }
			td a:hover{ border-bottom-color:var(--red); }

			.app{ display:flex; min-height:100vh; }
			.sidebar{ width:220px; max-width:85vw; background:var(--bg-sidebar); border-right:1px solid var(--border); flex-shrink:0; padding:22px 0; }
			.sidebar .brand{ padding:0 20px 24px; }
			.sidebar nav{ display:flex; flex-direction:column; }
			.sidebar nav a{ padding:10px 20px; font-size:13.5px; font-weight:400; color:var(--text-muted); text-decoration:none; border-left:3px solid transparent; }
			.sidebar nav a:hover{ color:#fff; }
			.sidebar nav a.active{ color:#fff; font-weight:700; background:var(--red-soft); border-left-color:var(--red); }
			.sidebar .nav-soon{ padding:10px 20px; font-size:13.5px; color:var(--text-faint); display:flex; justify-content:space-between; align-items:center; border-left:3px solid transparent; }
			.sidebar .nav-soon small{ font-size:9.5px; text-transform:uppercase; letter-spacing:.04em; background:var(--surface-alt); padding:2px 6px; border-radius:4px; }
			.sidebar-backdrop{ display:none; }
			.hamburger{ display:inline-flex; align-items:center; justify-content:center; background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--text); padding:7px 11px; cursor:pointer; flex-shrink:0; }
			.hamburger:hover{ border-color:var(--text-muted); color:#fff; }
			/* Desktop: collapse the sidebar and let the content reuse the space. */
			@media (min-width: 769px){
				.app.nav-hidden .sidebar{ display:none; }
				.app.nav-hidden main{ max-width:1480px; }
			}

			/* Brand logo lockup: dX icon mark + product name */
			.brand-lockup{ display:inline-flex; align-items:center; gap:11px; }
			.brand-lockup .brand-logo{ height:30px; width:auto; flex-shrink:0; display:block; }
			.brand-lockup .brand-name{ font-weight:700; font-size:15px; color:var(--dx-white); letter-spacing:.005em; }

			.app-main{ flex:1; min-width:0; }
			.topbar{ display:flex; justify-content:space-between; align-items:center; gap:12px; padding:16px 28px; border-bottom:1px solid var(--border); }
			.topbar .crumb{ font-size:13px; color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.topbar .crumb a{ color:var(--text-muted); }
			.topbar .crumb a:hover{ color:#fff; }
			.topbar .crumb .crumb-current{ color:var(--text); font-weight:700; }
			.topbar .crumb .crumb-sep{ color:var(--text-faint); margin:0 6px; }
			.topbar .user-menu{ font-size:13px; color:var(--text-muted); display:flex; align-items:center; gap:8px; flex-shrink:0; }
			.topbar .user-menu a{ text-decoration:none; }
			.topbar .user-menu a:hover{ color:#fff; }
			.user-badge{ background:var(--surface-alt); border:1px solid var(--border); border-radius:14px; padding:3px 12px; font-size:12px; color:var(--text); }

			/* Workspace switcher (topbar del plano de workspace): cambiar de
			   workspace sin cerrar sesión. El menú se carga por HTMX al abrirlo. */
			.ws-switch{ position:relative; flex-shrink:0; }
			.ws-switch-btn{ display:inline-flex; align-items:center; gap:7px; background:var(--surface-alt); border:1px solid var(--border); border-radius:14px; padding:3px 12px; font-family:var(--dx-font); font-size:12px; font-weight:400; text-transform:none; letter-spacing:0; color:var(--text); cursor:pointer; }
			.ws-switch-btn:hover{ border-color:var(--red); color:#fff; filter:none; }
			.ws-switch-caret{ font-size:10px; color:var(--text-muted); }
			.ws-switch-menu{ position:absolute; right:0; top:calc(100% + 8px); z-index:60; min-width:240px; max-width:min(320px,80vw); background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:12px; text-align:left; box-shadow:0 14px 30px rgba(0,0,0,.45); }
			.ws-switch-title{ margin:0 0 9px; font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.08em; color:var(--text-muted); }
			.ws-switch-loading,.ws-switch-empty{ margin:0 0 9px; font-size:12.5px; color:var(--text-muted); }
			.ws-switch-list{ list-style:none; margin:0 0 10px; padding:0; display:flex; flex-direction:column; gap:6px; max-height:290px; overflow-y:auto; }
			.ws-switch-item{ display:flex; align-items:center; justify-content:space-between; gap:10px; background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:9px 12px; font-size:13px; }
			a.ws-switch-item:hover{ border-color:var(--red); background:var(--surface-alt); }
			.ws-switch-item.is-current{ border-color:var(--red); }
			.ws-switch-item.is-disabled{ opacity:.55; }
			.ws-switch .ws-switch-name{ font-weight:700; color:var(--text); }
			.ws-switch-menu .ws-switch-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.ws-switch-all{ display:block; padding-top:10px; border-top:1px solid var(--border); text-align:center; font-size:12px; color:var(--text-muted); }
			.ws-switch-all:hover{ color:#fff; }

			main{ padding:28px; max-width:920px; }

			.region{ background:var(--surface); border:1px solid var(--border); border-radius:10px; margin-bottom:20px; overflow:hidden; }
			.region-head{ display:flex; flex-wrap:wrap; gap:10px; justify-content:space-between; align-items:center; padding:14px 20px; border-bottom:1px solid var(--border); }
			.region-head h2{ font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.08em; color:var(--text-muted); margin:0; }
			.region-body{ padding:18px 20px; }

			/* Variable-length tables: cap the height and scroll inside past the
			   limit (a more specific class like .data-scroll, or an inline
			   max-height, overrides this default). */
			.table-scroll{ overflow:auto; max-height:60vh; }
			/* Data grid: cap the height so a big table scrolls inside its panel
			   instead of stretching the page, with the header pinned on scroll. */
			.data-scroll{ overflow:auto; max-height:460px; }
			.data-scroll thead th{ position:sticky; top:0; z-index:2; }
			/* Cap each data-grid cell's width so a long value (a base64 fingerprint, a
			   big text blob) can't stretch the grid far off to the right. The value is
			   clipped with an ellipsis; the grid still scrolls horizontally inside
			   .data-scroll, and the full value shows on hover (title) or by
			   double-clicking an editable cell. */
			.data-scroll td{ max-width:260px; overflow:hidden; text-overflow:ellipsis; }
			.data-scroll th{ max-width:260px; }
			table{ width:100%; border-collapse:collapse; }
			th,td{ text-align:left; padding:11px 20px; border-bottom:1px solid var(--border); font-size:13.5px; white-space:nowrap; }
			th{ color:var(--text-muted); font-weight:700; font-size:11px; text-transform:uppercase; letter-spacing:.06em; background:var(--surface-alt); }
			/* Sortable column headers in the Object Browser data grid. */
			.col-sort{ display:inline-flex; align-items:center; gap:5px; color:inherit; text-decoration:none; cursor:pointer; border:none; }
			.col-sort:hover{ color:#fff; }
			.sort-glyph{ font-size:9px; opacity:.3; }
			.sort-glyph.is-active{ opacity:1; color:var(--red-light); }
			/* Inline cell edit: the span keeps its box (visibility:hidden) so the
			   column width never changes, and the input is overlaid to fill the
			   cell exactly. */
			.cell-host{ position:relative; }
			.cell-host .is-hidden{ visibility:hidden; }
			.cell-edit{ position:absolute; inset:0; margin:0; }
			.cell-input{ width:100%; height:100%; box-sizing:border-box; padding:4px 20px; font-size:13.5px; border-radius:0; }
			/* CodeMirror SQL editor: fit the dark theme and the panel. */
			.CodeMirror{ height:auto; min-height:160px; border:1px solid var(--border); border-radius:8px; font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:13px; }
			/* Compact CodeMirror variants that size to their content (no 160px
			   floor): inline read-only SQL in the REST handler rows, and the SQL
			   fields inside the add/edit handler forms. */
			.cm-inline{ flex:1 1 200px; min-width:0; }
			.cm-inline .CodeMirror{ min-height:0; }
			/* App Builder SQL fields sit inside flex .ab-form-row, where a width-less
			   CodeMirror collapses to its content and grows as you type. Pin it to a
			   fixed full-width, fixed-height box. */
			.ab-form .CodeMirror{ flex:1 1 100%; width:100%; height:170px; min-height:0; box-sizing:border-box; }
			.cm-field{ flex-basis:100%; }
			.cm-field .CodeMirror{ min-height:110px; } /* roomier editor for writing handler SQL */
			/* Expand-to-fullscreen (⛶) button, floated in each editor's corner.
			   Faint until the editor is hovered so it never competes with the code. */
			.cm-expand-btn{ position:absolute; top:6px; right:6px; z-index:6; display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; font-size:13px; line-height:1; background:var(--surface); color:var(--text-muted); border:1px solid var(--border); border-radius:5px; opacity:0; transition:opacity .12s ease, color .12s ease, border-color .12s ease; cursor:pointer; }
			.CodeMirror:hover .cm-expand-btn,.cm-expand-btn:focus-visible{ opacity:.85; }
			.cm-expand-btn:hover{ opacity:1; color:#fff; border-color:var(--text-muted); filter:none; }
			/* Object search (RESTful console): a scrollable list of hits, each a
			   row with the object name and its kind. Caps its height and scrolls. */
			.objsearch-results{ margin-top:10px; }
			.objsearch-list{ list-style:none; margin:0; padding:0; max-height:320px; overflow-y:auto; border:1px solid var(--border); border-radius:8px; background:var(--bg); }
			.objsearch-list li + li{ border-top:1px solid var(--border); }
			.objsearch-item{ display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; text-align:left; background:transparent; border:none; color:var(--text); padding:9px 12px; font-size:13px; text-transform:none; letter-spacing:0; font-weight:400; cursor:pointer; }
			.objsearch-item:hover{ background:var(--surface-alt); filter:none; }
			.objsearch-name{ font-family:ui-monospace,'SF Mono',Menlo,monospace; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.objsearch-kind{ flex:0 0 auto; }
			/* Detail panel shown after picking a hit — tidy for the narrow column:
			   a title row, a subtle "open" link, and a stacked column list (name +
			   type below it) instead of a wide 4-column table. */
			.objdetail{ margin-top:14px; padding-top:14px; border-top:1px solid var(--border); }
			.objdetail-head{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
			.objdetail-name{ font-weight:700; font-size:13.5px; overflow-wrap:anywhere; }
			.objdetail-open{ display:inline-flex; align-items:center; gap:5px; width:fit-content; margin-top:10px; padding:6px 11px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--text-muted); text-decoration:none; border:1px solid var(--border); border-radius:6px; }
			.objdetail-open:hover{ color:#fff; border-color:var(--text-muted); }
			.objdetail-sig{ margin:12px 0 0; font-size:11.5px; color:var(--text-muted); overflow-wrap:anywhere; }
			/* Compact one-line column rows: name (+ PK), with the data type revealed
			   on hover (also in the native title tooltip) so the list stays short. */
			.objdetail-cols{ list-style:none; margin:12px 0 0; padding:0; }
			.objdetail-col{ position:relative; display:flex; align-items:center; gap:6px; padding:7px 6px; border-bottom:1px solid var(--border); border-radius:6px; }
			.objdetail-col:last-child{ border-bottom:none; }
			.objdetail-col:hover{ background:var(--surface-alt); }
			.objdetail-col-name{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:12.5px; }
			.objdetail-col-type{ position:absolute; right:6px; top:50%; transform:translateY(-50%); max-width:78%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; background:var(--surface-alt); border:1px solid var(--border); border-radius:4px; padding:2px 7px; font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:10.5px; color:var(--text); opacity:0; pointer-events:none; transition:opacity .12s; }
			.objdetail-col:hover .objdetail-col-type{ opacity:1; }
			.objdetail-tag{ flex:0 0 auto; font-size:9px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:var(--text-muted); background:var(--surface-alt); border:1px solid var(--border); border-radius:4px; padding:1px 5px; }
			.objdetail-tag.pk{ color:var(--green); border-color:var(--green); }
			.objdetail-kv{ margin:12px 0 0; display:flex; flex-direction:column; gap:0; }
			.objdetail-kv > div{ display:flex; justify-content:space-between; gap:10px; padding:7px 2px; border-bottom:1px solid var(--border); font-size:12.5px; }
			.objdetail-kv > div:last-child{ border-bottom:none; }
			.objdetail-kv dt{ color:var(--text-muted); }
			.objdetail-kv dd{ margin:0; }
			.cm-detail{ margin-top:12px; }
			.cm-detail .CodeMirror{ min-height:0; }
			.cm-detail .CodeMirror-scroll{ max-height:300px; }
			/* Every editor grows with content up to a cap, then scrolls inside. */
			.CodeMirror-scroll{ max-height:50vh; }
			.cm-inline .CodeMirror-scroll{ max-height:200px; }
			.cm-field .CodeMirror-scroll{ max-height:300px; }
			kbd{ font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:11px; background:var(--surface-alt); border:1px solid var(--border); border-radius:4px; padding:1px 5px; }
			tbody tr:hover{ background:var(--surface-alt); }
			tbody tr:last-child td{ border-bottom:none; }

			button,.btn{ background:var(--red); color:var(--dx-white); border:none; border-radius:6px; padding:9px 18px; font-family:var(--dx-font); font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; cursor:pointer; }
			button:hover,.btn:hover{ filter:brightness(1.12); }
			button.secondary,a.btn.secondary{ background:transparent; color:var(--text-muted); border:1px solid var(--border); filter:none; }
			button.secondary:hover,a.btn.secondary:hover{ color:#fff; border-color:var(--text-muted); filter:none; }

			input,select{ background:var(--bg); border:1px solid var(--border); color:var(--text); font-family:var(--dx-font); padding:9px 11px; border-radius:6px; font-size:13.5px; }
			input::placeholder{ color:var(--text-faint); }
			input:focus,select:focus{ outline:none; border-color:var(--red); }
			/* REST handler source picker: a dropdown menu hidden until toggled. */
			.src-menu{ display:none; }
			.src-menu.open{ display:block; }
			.src-item:hover{ background:var(--surface-alt); }
			form.inline{ display:flex; flex-wrap:wrap; gap:8px; }
			form.inline input,form.inline select{ flex:1 1 140px; min-width:0; }
			form.inline button{ flex:0 0 auto; }

			@media (max-width: 768px){
				.sidebar{
					position:fixed; top:0; left:0; height:100vh; z-index:50; overflow-y:auto;
					transform:translateX(-100%); transition:transform .2s ease;
				}
				.sidebar.sidebar-open{ transform:translateX(0); }
				.hamburger{ display:inline-flex; align-items:center; border-radius:6px; color:var(--text); }
				.sidebar-backdrop{ display:block; position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:40; }
				.topbar{ padding:14px 16px; }
				main{ padding:16px; }
				.region-body{ padding:16px; }
				.region-head{ padding:12px 16px; }
				th,td{ padding:10px 14px; }
			}
			/* Tablet & down: stack the tree-and-detail split so the navigator sits
			   on top (full width, capped height) and the detail uses the full width
			   below it, instead of a cramped 248px column. */
			@media (max-width: 900px){
				.rest-layout{ flex-direction:column; }
				.rest-tree{ flex:0 0 auto; width:100%; position:static; top:auto; max-height:300px; }
				.rest-side{ flex:0 0 auto; width:100%; position:static; }
			}
			@media (max-width: 480px){
				.topbar{ flex-wrap:wrap; }
				.topbar .crumb{ max-width:100%; order:3; flex-basis:100%; white-space:normal; }
				/* El switcher comparte fila con el usuario: acortá el slug antes
				   que empujar el menú fuera de la pantalla. */
				.ws-switch .ws-switch-name{ max-width:90px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
				.ws-switch-menu{ min-width:0; width:min(300px,86vw); }
				form.inline input,form.inline select,form.inline button{ flex:1 1 100%; }
				.region-head{ flex-direction:column; align-items:stretch; }
				.region-head button,.region-head .btn,.region-head form{ width:100%; }
				.obj-tabs{ flex-wrap:nowrap; overflow-x:auto; }
				.select-box{ padding:30px 22px; }
				.modal-card{ padding:18px 16px; }
				main{ padding:14px; }
			}

			.badge{ display:inline-block; padding:2px 10px; border-radius:99px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; }
			.badge-active{ background:rgba(63,184,115,.15); color:var(--green); }
			.badge-disabled{ background:var(--red-soft); color:var(--red-light); }
			.badge-method{ background:var(--surface-alt); color:var(--text-muted); }
			/* Method-coloured badges, matching the tree palette */
			.badge-method.m-GET{ background:rgba(63,184,115,.15); color:#7fd0a8; }
			.badge-method.m-POST{ background:rgba(224,192,116,.15); color:#e0c074; }
			.badge-method.m-PUT,.badge-method.m-PATCH{ background:rgba(127,174,217,.15); color:#7faed9; }
			.badge-method.m-DELETE{ background:var(--red-soft); color:var(--red-light); }

			/* RESTful Services console (Phase 2) */
			main.wide{ max-width:1180px; }
			a.btn{ display:inline-block; text-decoration:none; line-height:1; }

			/* HTMX loading indicator: an element with class .htmx-indicator is hidden
			   until a request its trigger drives is in flight, then faded in. Used by
			   the data import, where a big file takes a few seconds and the user needs
			   to see that something is happening. */
			.htmx-indicator{ opacity:0; transition:opacity .15s ease; }
			.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{ opacity:1; }
			.spinner{ display:inline-block; width:15px; height:15px; border:2px solid var(--border); border-top-color:var(--red-light); border-radius:50%; animation:spin .7s linear infinite; vertical-align:middle; }
			@keyframes spin{ to{ transform:rotate(360deg); } }

			/* Data-transfer console forms: fields in a row, each a normal-height input.
			   (The generic form.inline rule sets `flex:1 1 140px` on inputs, which —
			   inside these column-direction labels — becomes a 140px HEIGHT, making the
			   inputs tall squares. This class opts out of that.) */
			.tf-form{ display:flex; flex-wrap:wrap; gap:12px 14px; align-items:flex-end; }
			.tf-form > label{ display:flex; flex-direction:column; gap:4px; font-size:11px; color:var(--text-muted); }
			.tf-form input,.tf-form select{ flex:0 0 auto; min-width:190px; }
			/* Small inline "loading" hint shown while a schema/table change re-fetches
			   its list (htmx-indicator: hidden until the request is in flight). */
			.tf-spin{ display:inline-flex; align-items:center; gap:6px; font-size:11px; color:var(--text-muted); align-self:center; }
			/* Destination-conflict panel: shown when the chosen destination table
			   already has rows, offering what to do with the existing data. */
			.tf-conflict{ margin-top:14px; padding:14px 16px; border:1px solid var(--border); border-radius:8px; background:var(--bg); }
			.tf-conflict h4{ margin:0 0 4px; font-size:13px; font-weight:700; color:var(--text); }
			.tf-modes{ display:flex; flex-direction:column; gap:8px; margin-top:10px; }
			.tf-mode{ display:flex; gap:9px; align-items:flex-start; padding:9px 12px; border:1px solid var(--border); border-radius:7px; cursor:pointer; }
			.tf-mode:hover{ border-color:var(--text-muted); }
			.tf-mode input{ margin-top:2px; width:auto; min-width:0; flex:0 0 auto; }
			.tf-mode-title{ font-size:13px; font-weight:600; color:var(--text); }
			.tf-mode-count{ display:inline-block; margin-left:8px; padding:1px 9px; border-radius:999px; font-size:11.5px; font-weight:600; color:var(--text); background:var(--surface-alt); border:1px solid var(--border); vertical-align:middle; white-space:nowrap; }
			.tf-mode-count.add{ color:var(--green); border-color:var(--green); }
			/* Single-table / multi-table mode switch. */
			.tf-tabs{ display:flex; align-items:center; gap:4px; margin-top:10px; border-bottom:1px solid var(--border); }
			.tf-tab{ appearance:none; background:none; border:none; border-bottom:2px solid transparent; margin:0; padding:7px 12px; font-size:12.5px; font-weight:600; color:var(--text-muted); cursor:pointer; border-radius:0; }
			.tf-tab:hover{ color:var(--text); }
			.tf-tab.active{ color:var(--text); border-bottom-color:var(--red); }
			/* Multi-table checklist. */
			table.tf-bulk{ width:100%; border-collapse:collapse; font-size:12.5px; }
			table.tf-bulk th{ text-align:left; font-size:11px; color:var(--text-muted); font-weight:600; padding:6px 10px; border-bottom:1px solid var(--border); white-space:nowrap; }
			table.tf-bulk td{ padding:6px 10px; border-bottom:1px solid var(--border); }
			table.tf-bulk input[type=checkbox]{ width:auto; min-width:0; vertical-align:middle; }
			.tf-nokey{ display:inline-block; margin-left:8px; padding:0 7px; border-radius:999px; font-size:10.5px; color:var(--text-muted); background:var(--surface-alt); border:1px solid var(--border); }
			.tf-mode-desc{ font-size:12px; color:var(--text-muted); }
			/* Live transfer progress bar. */
			.tf-progress{ height:10px; background:var(--surface-alt); border:1px solid var(--border); border-radius:6px; overflow:hidden; max-width:520px; }
			.tf-progress-bar{ height:100%; background:var(--red); border-radius:6px; transition:width .5s ease; }

			/* Upload progress. Any multipart form gets this while its file travels
			   (see app.js): without it a big file looks like a tab that reloads for a
			   minute with nothing to show for it. Reuses the transfer bar's shape so
			   the two read as the same thing. */
			.app-upload{ margin-top:10px; max-width:520px; font-size:12.5px; color:var(--text-muted); }
			.app-upload-bar{ height:10px; background:var(--surface-alt); border:1px solid var(--border); border-radius:6px; overflow:hidden; }
			.app-upload-fill{ height:100%; width:0; background:var(--red); border-radius:6px; transition:width .2s linear; }
			.app-upload-text{ margin-top:6px; display:flex; justify-content:space-between; gap:12px; }
			/* Once the bytes are all sent the server is still working and there is no
			   percentage left to report, so the bar says so by sweeping instead of
			   pretending to advance. */
			.app-upload.is-working .app-upload-fill{
				width:35%; animation:app-upload-sweep 1.1s ease-in-out infinite;
			}
			@keyframes app-upload-sweep{
				0%{ margin-left:0 } 50%{ margin-left:65% } 100%{ margin-left:0 }
			}

			/* Object detail action toolbar: safe actions first, then the destructive
			   ones (Truncar / Eliminar) grouped behind a divider so they don't sit
			   flush with the rest. */
			.obj-actions{ display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:0; }
			.obj-actions form{ margin:0; display:flex; align-items:center; gap:6px; }
			.obj-actions .danger-zone{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-left:2px; padding-left:12px; border-left:1px solid var(--border); }
			.inline-check{ display:inline-flex; align-items:center; gap:5px; font-size:11px; color:var(--text-muted); text-transform:none; letter-spacing:0; font-weight:400; }
			.inline-check input{ width:auto; vertical-align:middle; }
			button.danger{ background:transparent; color:var(--red-light); border:1px solid var(--red-soft); filter:none; }
			button.danger:hover{ background:var(--red-soft); border-color:var(--red-light); color:#fff; filter:none; }

			/* Data-tab footer: the "insert row" and "import data" panels laid out as a
			   tidy pair of cards with a consistent header, instead of two loose toggles. */
			.data-actions{ display:flex; flex-wrap:wrap; gap:14px; padding:16px 20px; border-top:1px solid var(--border); }
			.data-action{ flex:1 1 280px; background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:15px 16px; }
			.data-action-head{ display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
			.data-action h4{ margin:0; font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--text); }
			.data-action p{ margin:6px 0 0; font-size:12px; color:var(--text-muted); line-height:1.45; }
			.import-drop{ display:flex; flex-direction:column; gap:10px; margin-top:12px; }
			.import-drop input[type=file]{ width:100%; font-size:12.5px; }
			.import-drop input[type=file]::file-selector-button{ background:var(--surface-alt); color:var(--text); border:1px solid var(--border); border-radius:6px; padding:7px 12px; font-family:var(--dx-font); font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; margin-right:10px; cursor:pointer; }
			.import-drop input[type=file]::file-selector-button:hover{ border-color:var(--text-muted); }
			.import-row{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
			.import-progress{ display:inline-flex; align-items:center; gap:9px; font-size:12.5px; color:var(--text-muted); }

			/* Object Browser detail tabs (Phase 3) */
			.obj-tabs{ display:flex; flex-wrap:wrap; gap:4px; border-bottom:1px solid var(--border); }
			.obj-tab{ padding:9px 14px; font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--text-muted); cursor:pointer; background:transparent; border:none; border-bottom:2px solid transparent; margin-bottom:-1px; }
			.obj-tab:hover{ color:#fff; }
			.obj-tab.is-active{ color:#fff; border-bottom-color:var(--red); }
			tr.row-clickable{ cursor:pointer; }

			/* ORDS-style module tree */
			.rest-layout{ display:flex; gap:18px; align-items:flex-start; }
			.rest-main{ flex:1; min-width:0; }
			.rest-tree{ flex:0 0 248px; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:12px 8px; position:sticky; top:18px; max-height:calc(100vh - 96px); overflow:auto; }
			/* Left column that stacks the REST navigator and the object search below
			   it (a separate box). The tree keeps its own scroll; the search sits
			   under it. Sticky as a unit so it follows while the main content scrolls. */
			/* The whole left column scrolls as ONE region (no nested inner scrolls
			   that would trap the wheel), so a long detail is fully reachable. */
			.rest-side{ flex:0 0 248px; align-self:flex-start; position:sticky; top:18px; display:flex; flex-direction:column; gap:16px; max-height:calc(100vh - 36px); overflow-y:auto; overflow-x:hidden; }
			.rest-side .rest-tree{ flex:0 0 auto; width:auto; position:static; top:auto; max-height:none; overflow:visible; }
			.rest-side .region{ margin-bottom:0; }
			/* Cap the SQL results panel height; it scrolls internally past that. */
			.results-scroll{ max-height:60vh; overflow-y:auto; }
			.tree-title{ font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.09em; color:var(--text-muted); padding:4px 8px 10px; }
			.tree, .tree ul{ list-style:none; margin:0; padding:0; }
			.tree-row{ display:flex; align-items:center; gap:5px; padding:4px 6px; border-radius:6px; font-size:13px; color:var(--text); white-space:nowrap; }
			a.tree-row{ text-decoration:none; }
			.tree-row:hover{ background:var(--surface-alt); }
			.tree-row.is-active{ background:var(--red-soft); }
			.tree-row.is-active > .tree-link{ color:#fff; font-weight:700; }
			.tree-caret{ width:13px; text-align:center; color:var(--text-muted); cursor:pointer; font-size:10px; flex:0 0 auto; user-select:none; }
			.tree-caret.empty{ cursor:default; color:var(--text-faint); }
			.tree-link{ color:var(--text); text-decoration:none; overflow:hidden; text-overflow:ellipsis; }
			.tree-link:hover{ color:#fff; }
			.tree-leaf{ color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; }
			.tree-clickable{ cursor:pointer; }
			/* Sub-group header inside the tree (e.g. "Vistas" / "Triggers"): a small
			   uppercase label, clickable to expand/collapse, clearly distinct from
			   the object rows below it. */
			.tree-group{ cursor:pointer; }
			.tree-sublabel{ font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.08em; color:var(--text-muted); }
			.tree-group:hover .tree-sublabel{ color:#fff; }
			.tree-children{ padding-left:18px; border-left:2px solid var(--border); margin-left:14px; }
			.tree-lock{ font-size:10px; flex:0 0 auto; }
			.tree-method{ font-size:9px; font-weight:700; padding:1px 5px; border-radius:4px; background:var(--surface-alt); color:var(--text-muted); letter-spacing:.03em; flex:0 0 auto; }
			.tree-method.m-GET{ color:#7fd0a8; }
			.tree-method.m-POST{ color:#e0c074; }
			.tree-method.m-PUT,.tree-method.m-PATCH{ color:#7faed9; }
			.tree-method.m-DELETE{ color:var(--red-light); }
			/* Per-category colours for the object-tree labels (section titles AND the
			   "Vistas"/"Triggers" sub-labels nested under each table), so each object
			   type is distinguishable at a glance — same palette as the method badges.
			   Defined last so they win over .tree-title / .tree-sublabel (same
			   specificity, later in source). */
			.cat-tables{ color:#7faed9; }
			.cat-views{ color:#7fd0a8; }
			.cat-seqs{ color:#e0c074; }
			.cat-fns{ color:#b794f6; }
			.cat-triggers{ color:#e8956b; }
			/* Keep the category colour on hover instead of the default white. */
			.tree-group:hover .tree-sublabel.cat-views{ color:#7fd0a8; }
			.tree-group:hover .tree-sublabel.cat-triggers{ color:#e8956b; }

			.tpl-card{ border:1px solid var(--border); border-radius:8px; margin-bottom:14px; overflow:hidden; }
			.tpl-card:last-child{ margin-bottom:0; }
			.tpl-head{ display:flex; flex-wrap:wrap; gap:8px 14px; align-items:baseline; padding:11px 14px; background:var(--surface-alt); border-bottom:1px solid var(--border); }
			.tpl-meta{ font-size:11.5px; color:var(--text-muted); }
			.tpl-del{ margin-left:auto; padding:5px 12px; }
			code.src{ display:inline-block; max-width:100%; white-space:pre-wrap; word-break:break-word; }
			.tpl-add{ padding:12px 14px; border-top:1px solid var(--border); }

			/* Editable handler rows */
			.handler-row{ padding:11px 14px; border-top:1px solid var(--border); }
			.handler-summary{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
			.handler-summary .src{ flex:1 1 200px; min-width:0; }
			.handler-actions{ margin-left:auto; display:flex; gap:6px; flex-wrap:wrap; white-space:nowrap; }
			/* Handler source preview: full width of the row, a fixed height that does
			   not depend on the buttons beside it, nothing crammed to its sides. */
			.cm-handler{ width:100%; margin-top:10px; }
			.cm-handler .CodeMirror{ width:100%; height:170px; min-height:0; }
			.cm-handler .CodeMirror-scroll{ max-height:none; }
			.handler-edit{ display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; padding-top:11px; border-top:1px dashed var(--border); }
			.handler-edit select,.handler-edit input,.handler-edit button{ flex:0 0 auto; }

			.error{ color:var(--red-light); font-size:13.5px; }
			code{ font-family:ui-monospace,'SF Mono',Menlo,monospace; background:var(--surface-alt); border:1px solid var(--border); padding:1px 6px; border-radius:4px; font-size:.86em; color:#d8dbd2; }
			pre{ font-family:ui-monospace,'SF Mono',Menlo,monospace; background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:14px; font-size:13px; color:#d8dbd2; white-space:pre-wrap; word-break:break-word; min-height:20px; margin:0; }
			/* Script version diff (SQL Commands): a unified line diff, removed lines
			   tinted red and added lines green, gutter marker per line. */
			.diff-view{ font-family:ui-monospace,'SF Mono',Menlo,monospace; background:var(--bg); border:1px solid var(--border); border-radius:8px; font-size:12.5px; color:#d8dbd2; max-height:52vh; overflow:auto; padding:6px 0; }
			.diff-line{ display:flex; gap:8px; padding:1px 12px; white-space:pre-wrap; word-break:break-word; }
			.diff-gutter{ flex:0 0 12px; text-align:center; color:var(--text-faint); user-select:none; }
			.diff-add{ background:rgba(63,184,115,.14); }
			.diff-add .diff-gutter{ color:var(--green); }
			.diff-del{ background:var(--red-soft); }
			.diff-del .diff-gutter{ color:var(--red-light); }
			/* The "Probar" result can return many rows: cap its height and scroll. */
			.json-view{ max-height:60vh; overflow:auto; }
			/* JSON viewer tokens for the "Probar" result (Chrome-style highlight). */
			.json-key{ color:#d9685a; }
			.json-str{ color:#3FB873; }
			.json-num{ color:#cda35a; }
			.json-bool{ color:#5aa6d9; }
			.json-null{ color:var(--text-faint); }

			.login-page{ min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:20px; }
			.login-box{ width:100%; max-width:340px; background:var(--surface); border:1px solid var(--border); padding:32px; border-radius:10px; }
			.login-box .brand{ margin:0 0 24px; }
			.login-box .brand-name{ font-size:17px; }
			.login-box label{ display:block; font-size:12.5px; color:var(--text-muted); margin-bottom:14px; }
			.login-box input{ width:100%; margin-top:6px; }
			.login-box button{ width:100%; padding:11px; margin-top:6px; }
			.login-box .error{ margin-top:0; }
			.login-version{ margin:0; font-size:11.5px; letter-spacing:.02em; color:var(--text-faint); }

			/* Alpine cloak: hide modal markup until Alpine initialises */
			[x-cloak]{ display:none !important; }
			.muted{ font-size:12.5px; color:var(--text-muted); margin:8px 0; }

			/* Modal (create workspace) */
			.modal{ position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center; padding:20px; }
			.modal-backdrop{ position:absolute; inset:0; background:rgba(0,0,0,.6); }
			.modal-card{ position:relative; z-index:1; width:100%; max-width:440px; max-height:90vh; overflow-y:auto; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:22px 24px; }
			.modal-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
			.modal-head h3{ margin:0; font-size:15px; font-weight:700; color:var(--text); }
			.modal-close{ padding:4px 9px; font-size:12px; }
			.modal-form label{ display:block; font-size:12.5px; color:var(--text-muted); margin-bottom:12px; }
			.modal-form input[type=text],.modal-form input[type=password]{ width:100%; margin-top:6px; }
			.modal-actions{ display:flex; gap:8px; justify-content:flex-end; margin-top:18px; }

			/* Segmented toggle: usuario nuevo / existente */
			.seg{ display:flex; gap:6px; margin:4px 0 14px; }
			.seg-opt{ flex:1; background:var(--bg); color:var(--text-muted); border:1px solid var(--border); border-radius:6px; padding:9px 10px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; cursor:pointer; }
			.seg-opt:hover{ color:#fff; }
			.seg-opt.is-active{ background:var(--red-soft); border-color:var(--red); color:#fff; }

			/* Existing-user search results */
			.acc-results{ margin:0 0 8px; }
			.acc-list{ list-style:none; margin:0; padding:0; border:1px solid var(--border); border-radius:6px; overflow:hidden; }
			.acc-list li + li{ border-top:1px solid var(--border); }
			.acc-result{ width:100%; text-align:left; background:transparent; color:var(--text); border:none; border-radius:0; padding:9px 12px; font-size:13px; font-weight:400; text-transform:none; letter-spacing:0; }
			.acc-result:hover{ background:var(--surface-alt); filter:none; }
			.acc-empty{ font-size:12.5px; color:var(--text-faint); margin:0 0 8px; }
			.acc-selected{ font-size:12.5px; color:var(--text-muted); margin:4px 0 0; }

			/* Select-workspace page (post-login, APEX-style) */
			.select-page{ min-height:100vh; display:flex; align-items:center; justify-content:center; padding:20px; }
			.select-box{ width:100%; max-width:480px; background:var(--surface); border:1px solid var(--border); padding:44px 48px; border-radius:12px; text-align:center; }
			.select-box .brand{ margin:0 0 26px; display:flex; justify-content:center; }
			.select-box .brand-name{ font-size:18px; }
			.select-user{ display:inline-flex; align-items:center; gap:8px; background:var(--surface-alt); border:1px solid var(--border); border-radius:16px; padding:6px 16px; margin-bottom:22px; }
			.select-user-name{ font-size:14px; font-weight:700; color:var(--text); }
			.select-hint{ font-size:13px; color:var(--text-muted); margin:0 0 16px; }
			.ws-pick{ list-style:none; margin:0 0 18px; padding:0; display:flex; flex-direction:column; gap:8px; text-align:left; }
			.ws-pick-item{ display:flex; align-items:center; justify-content:space-between; gap:10px; background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:13px 15px; }
			.ws-pick-item:hover{ border-color:var(--red); background:var(--surface-alt); }
			.ws-pick-name{ font-size:14px; font-weight:700; color:var(--text); }
			.badge-admin{ display:inline-block; padding:2px 9px; border-radius:99px; font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; background:var(--red-soft); color:var(--red-light); }
			.select-signout{ display:inline-block; width:100%; text-align:center; }

			/* ── Swagger UI: dark theme (API Docs) ─────────────────────────
			   Lives in its own sheet (static/swagger-dark.css) because it has to
			   load AFTER the Swagger CDN stylesheet to win the specificity ties;
			   app.css is in <head>, i.e. before it. See that file for the rules. */

			/* ── Phase 4 · App Builder ─────────────────────────────────────── */
			.ab-cards{ display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:14px; }
			.ab-card{ display:block; background:var(--surface-alt); border:1px solid var(--border); border-radius:10px; padding:16px 18px; text-decoration:none; color:var(--text); transition:border-color .12s ease, transform .12s ease; }
			.ab-card:hover{ border-color:var(--red); transform:translateY(-1px); }
			.ab-card-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:8px; }
			.ab-card-name{ font-weight:700; font-size:15px; }
			.ab-card-alias{ font-size:11.5px; color:var(--text-muted); word-break:break-all; }

			/* End-user app runtime (/app/{ws}/{alias}/{page}) */
			.app-runtime{ min-height:100vh; background:var(--bg); color:var(--text); display:flex; flex-direction:column; }
			.app-runtime-top{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:14px 26px; background:var(--bg-sidebar); border-bottom:1px solid var(--border); }
			.app-runtime-brand{ display:flex; align-items:center; gap:12px; }
			.app-runtime-appname{ font-weight:700; font-size:15px; }
			.app-runtime-ws{ font-size:11.5px; color:var(--text-muted); }
			.app-runtime-main{ flex:1 1 auto; width:100%; max-width:1600px; margin:0 auto; padding:26px; box-sizing:border-box; }
			.app-runtime-pagehead{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:20px; border-bottom:1px solid var(--border); padding-bottom:14px; }
			.app-runtime-pagehead h1{ font-size:24px; font-weight:700; margin:0; }
			.app-runtime-pageno{ font-size:11.5px; color:var(--text-muted); white-space:nowrap; }
			/* Regions render absolutely-positioned in the same free-form canvas as
			   the designer, so a designed page looks identical when it runs. */
			.app-runtime-scroll{ width:100%; }
			/* The runtime canvas fills the available width; regions are positioned as
			   a percentage of the page width, so the layout scales to the viewport and
			   a full-width region fills the whole width (no fixed px, no page scroll). */
			.app-runtime-canvas{ position:relative; width:100%; }
			.app-runtime-region-pos{ position:absolute; box-sizing:border-box; }
			.app-runtime-region-pos > .app-runtime-region{ margin:0; width:100%; height:100%; box-sizing:border-box; overflow:hidden; padding:0; }
			.app-runtime-region-scroll{ position:absolute; inset:0; overflow:auto; padding:16px 18px; }
			.app-runtime-item{ position:absolute; z-index:3; box-sizing:border-box; }
			/* A positioned item's control fills the box the user sized in the layout,
			   so resizing the item resizes its input (not a fixed min-width). */
			.app-runtime-item .app-runtime-filter{ margin:0; width:100%; height:100%; }
			.app-runtime-item .app-runtime-filter input,
			.app-runtime-item .app-runtime-filter select,
			.app-runtime-item .app-runtime-filter textarea,
			.app-runtime-item .app-runtime-display{ width:100%; min-width:0; box-sizing:border-box; }
			.app-runtime-item .app-runtime-filter textarea{ flex:1 1 auto; resize:none; }
			.app-runtime-region{ background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:18px 20px; margin-bottom:18px; }
			.app-runtime-region h2{ font-size:13px; font-weight:700; margin:0 0 10px; }
			.app-runtime-empty{ background:var(--surface); border:1px dashed var(--border); border-radius:10px; padding:32px; text-align:center; }
			.app-runtime-empty p{ margin:0 0 6px; }
			/* Modal dialog pages: an overlay iframe (opened by a data-modal link) and
			   the chrome-less page rendered inside it. */
			.app-modal-overlay{ position:fixed; inset:0; z-index:1000; background:rgba(10,12,10,.62); display:flex; align-items:flex-start; justify-content:center; padding:5vh 16px; }
			.app-modal-frame{ width:100%; max-width:860px; height:70vh; border:1px solid var(--border); border-radius:14px; background:var(--bg); box-shadow:0 26px 80px rgba(0,0,0,.55); }
			.app-modal-bar{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:14px 22px; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--bg); z-index:2; }
			.app-modal-bar h2{ margin:0; font-size:16px; font-weight:700; }
			.app-modal-x{ background:transparent; border:1px solid var(--border); color:var(--text-muted); border-radius:8px; width:32px; height:32px; font-size:14px; cursor:pointer; line-height:1; }
			.app-modal-x:hover{ color:var(--text); border-color:var(--text-muted); }
			.app-modal-page .app-runtime-main{ padding:20px 22px; max-width:none; }
			/* Inside a dialog the free-form canvas flows to its natural height (like
			   the narrow-screen stacking), so the modal fits its content. */
			.app-modal-page .app-runtime-canvas{ display:flex; flex-direction:column; gap:16px; height:auto!important; }
			.app-modal-page .app-runtime-region-pos{ position:static!important; left:auto!important; top:auto!important; width:100%!important; height:auto!important; }
			.app-modal-page .app-runtime-region-pos > .app-runtime-region{ height:auto; overflow:visible; display:flex; flex-direction:column; }
			.app-modal-page .app-runtime-region-scroll{ position:static!important; inset:auto!important; top:auto!important; overflow:visible; order:2; }
			.app-modal-page .app-runtime-item{ position:static!important; left:auto!important; top:auto!important; width:100%!important; height:auto!important; order:1; margin:0 0 10px; }
			/* Page-level button bar (below the filters) and per-region button footer. */
			.app-runtime-buttonbar{ display:flex; align-items:center; gap:10px; margin-bottom:18px; }
			.app-runtime-buttonbar .ab-btns-left{ display:flex; gap:10px; }
			.app-runtime-buttonbar .ab-btns-right{ display:flex; gap:10px; margin-left:auto; }
			.app-runtime-region-buttons{ display:flex; flex-wrap:wrap; gap:10px; margin-top:14px; }
			.app-runtime-btn{ text-decoration:none; }
			/* Dynamic Actions: an item/region disabled by an action, and a filter
			   marked required (a red * after its label). */
			.app-runtime-region-pos.is-disabled{ opacity:.5; pointer-events:none; }
			.app-runtime-item.is-disabled input, .app-runtime-item.is-disabled select, .app-runtime-item.is-disabled textarea,
			.app-runtime-filter.is-disabled input, .app-runtime-filter.is-disabled select, .app-runtime-filter.is-disabled textarea{ opacity:.55; }
			.app-runtime-filter.is-required > span:first-child::after{ content:" *"; color:var(--red-light,#e0715f); font-weight:700; }
			/* Narrow screens (phones/tablets): the free-form canvas collapses to a
			   single column. Regions stop being absolutely positioned, span the full
			   width, and stack in reading order (top, then left) via their `order`.
			   Floating region items flow above their region's content. */
			@media (max-width:760px){
				.app-runtime-main{ padding:16px; }
				.app-runtime-canvas{ display:flex; flex-direction:column; gap:16px; height:auto!important; }
				.app-runtime-region-pos{ position:static!important; left:auto!important; top:auto!important; width:100%!important; height:auto!important; }
				.app-runtime-region-pos > .app-runtime-region{ height:auto; overflow:visible; display:flex; flex-direction:column; }
				.app-runtime-region-scroll{ position:static!important; inset:auto!important; top:auto!important; overflow:visible; order:2; }
				.app-runtime-item{ position:static!important; left:auto!important; top:auto!important; width:100%!important; height:auto!important; order:1; margin:0 0 10px; }
				.app-runtime-item .app-runtime-filter{ height:auto; }
			}

			/* App Builder · page designer forms + runtime report */
			.ab-form{ display:flex; flex-direction:column; gap:10px; }
			.ab-form-row{ display:flex; flex-wrap:wrap; gap:10px; align-items:center; }
			.app-runtime-filters{ display:flex; flex-wrap:wrap; gap:14px; align-items:flex-end; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:14px 16px; margin-bottom:18px; }
			.app-runtime-filter{ display:flex; flex-direction:column; gap:4px; font-size:11.5px; color:var(--text-muted); }
			.app-runtime-filter input{ min-width:180px; }
			/* Extended page-item controls (radio/switch/color/slider/stars/richtext/image). */
			.app-runtime-radio{ display:flex; flex-wrap:wrap; gap:6px 14px; }
			.app-runtime-radio-opt{ display:inline-flex; align-items:center; gap:5px; font-size:13px; color:var(--text); }
			.app-runtime-radio-opt input{ min-width:0; width:auto; margin:0; }
			.app-runtime-switch{ position:relative; display:inline-flex; align-items:center; width:44px; height:24px; }
			.app-runtime-switch input{ position:absolute; opacity:0; width:100%; height:100%; margin:0; cursor:pointer; }
			.app-runtime-switch-track{ position:absolute; inset:0; background:var(--surface-alt); border:1px solid var(--border); border-radius:999px; transition:background .15s ease; }
			.app-runtime-switch-track::after{ content:""; position:absolute; top:2px; left:2px; width:18px; height:18px; border-radius:50%; background:var(--text-muted); transition:transform .15s ease, background .15s ease; }
			.app-runtime-switch input:checked + .app-runtime-switch-track{ background:var(--red); border-color:var(--red); }
			.app-runtime-switch input:checked + .app-runtime-switch-track::after{ transform:translateX(20px); background:#fff; }
			.app-runtime-slider{ display:inline-flex; align-items:center; gap:10px; }
			.app-runtime-slider input[type=range]{ min-width:160px; }
			.app-runtime-slider output{ font-size:12.5px; color:var(--text); min-width:2ch; text-align:right; }
			.app-runtime-stars{ display:inline-flex; gap:2px; }
			.app-runtime-star{ background:none; border:none; padding:0 1px; font-size:19px; line-height:1; color:var(--border); cursor:pointer; transition:color .1s ease; }
			.app-runtime-star:hover, .app-runtime-star.on{ color:#e8b923; }
			.app-runtime-filter input[type=color]{ min-width:0; width:44px; height:30px; padding:2px; border:1px solid var(--border); border-radius:6px; background:var(--surface-alt); cursor:pointer; }
			.app-runtime-richtext{ display:flex; flex-direction:column; gap:6px; }
			.app-runtime-richtext-toolbar{ display:flex; gap:4px; }
			.app-runtime-richtext-toolbar button{ width:26px; height:26px; padding:0; font-size:13px; background:var(--surface-alt); color:var(--text); border:1px solid var(--border); border-radius:5px; cursor:pointer; }
			.app-runtime-richtext-toolbar button:hover{ border-color:var(--text-muted); }
			.app-runtime-richtext-editor{ min-height:96px; min-width:220px; padding:8px 10px; background:var(--surface-alt); border:1px solid var(--border); border-radius:7px; font-size:13.5px; color:var(--text); overflow:auto; }
			.app-runtime-richtext-editor:focus{ outline:none; border-color:var(--red); }
			.app-runtime-image{ max-width:100%; max-height:220px; border-radius:8px; border:1px solid var(--border); }
			.app-runtime-pager{ display:flex; align-items:center; gap:12px; margin-top:12px; }
			.app-runtime-pageinfo{ font-size:12px; color:var(--text-muted); }

			/* App Builder · runtime Form region */
			.app-runtime-region-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:10px; }
			.app-runtime-region-head h2{ margin:0; }
			.app-runtime-form{ display:flex; flex-direction:column; gap:12px; max-width:560px; }
			.app-runtime-field{ display:flex; flex-direction:column; gap:4px; font-size:12px; color:var(--text-muted); }
			.app-runtime-field .req{ color:var(--red-light); }
			.app-runtime-field input[type=checkbox]{ width:auto; }
			.app-runtime-formactions{ display:flex; gap:10px; margin-top:4px; }
			.app-runtime-formerr{ background:var(--red-soft); border:1px solid var(--red); border-radius:8px; padding:10px 14px; font-size:12.5px; }

			/* App Builder · Interactive Report */
			.ir-toolbar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:12px; }
			.ir-toolbar .ir-search{ flex:1 1 240px; min-width:180px; }
			.ir-toolbar select{ flex:0 0 auto; width:auto; }
			.ir-sort{ color:var(--text); text-decoration:none; display:inline-flex; align-items:center; gap:5px; white-space:nowrap; }
			.ir-sort:hover{ color:var(--red); }
			.ir-ind{ color:var(--red); font-size:10px; }
			/* App Builder · Interactive Report column filters + aggregates */
			.ir-filterbar{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; margin-bottom:12px; }
			.ir-chips{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
			.ir-chips-label{ font-size:12px; color:var(--text-muted); }
			.ir-chip{ display:inline-flex; align-items:center; gap:6px; font-size:12px; background:var(--bg); border:1px solid var(--border); border-radius:999px; padding:3px 6px 3px 10px; white-space:nowrap; }
			.ir-chip-x{ color:var(--text-muted); text-decoration:none; font-weight:700; line-height:1; padding:0 4px; border-radius:999px; }
			.ir-chip-x:hover{ color:#fff; background:var(--red); }
			.ir-addfilter{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
			.ir-addfilter select{ width:auto; flex:0 0 auto; }
			.ir-addfilter .ir-filter-val{ flex:0 0 140px; }
			.ir-agg-row td{ font-weight:700; border-top:2px solid var(--border); background:color-mix(in srgb, var(--red) 6%, transparent); }
			.ir-agg-label{ color:var(--red); text-align:center; }
			/* App Builder · Interactive Report saved views + column control */
			.ir-viewsbar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:12px; }
			.ir-views-label{ font-size:12px; color:var(--text-muted); }
			.ir-view-chip{ display:inline-flex; align-items:center; gap:2px; font-size:12px; background:var(--bg); border:1px solid var(--border); border-radius:999px; padding:2px 4px 2px 4px; }
			.ir-view-load{ display:inline-flex; align-items:center; gap:5px; color:var(--text); text-decoration:none; padding:2px 8px; border-radius:999px; }
			.ir-view-load:hover{ color:var(--red); }
			.ir-view-star{ color:var(--red); }
			.ir-view-actions{ display:inline-flex; align-items:center; }
			.ir-view-x{ background:none; border:none; color:var(--text-muted); cursor:pointer; font-size:13px; line-height:1; padding:2px 4px; border-radius:999px; }
			.ir-view-x:hover{ color:#fff; background:var(--red); }
			.ir-menu{ position:relative; display:inline-block; }
			.ir-menu > summary{ list-style:none; cursor:pointer; }
			.ir-menu > summary::-webkit-details-marker{ display:none; }
			.ir-menu-panel{ position:absolute; z-index:30; top:calc(100% + 6px); left:0; min-width:240px; background:var(--surface,var(--bg)); border:1px solid var(--border); border-radius:10px; box-shadow:0 12px 30px rgba(0,0,0,.28); padding:10px; }
			.ir-save-menu .ir-menu-panel{ right:0; left:auto; }
			.ir-col-row{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:3px 4px; border-radius:6px; }
			.ir-col-row:hover{ background:var(--bg); }
			.ir-col-toggle{ display:inline-flex; align-items:center; gap:8px; color:var(--text); text-decoration:none; font-size:13px; flex:1 1 auto; }
			.ir-col-check{ color:var(--text-muted); } .ir-col-check.on{ color:var(--red); }
			.ir-col-moves{ display:inline-flex; gap:6px; }
			.ir-col-moves a{ color:var(--text-muted); text-decoration:none; font-weight:700; padding:0 3px; }
			.ir-col-moves a:hover{ color:var(--red); }
			.ir-save-name{ display:block; width:100%; margin-bottom:8px; }
			.ir-save-default{ display:flex; align-items:center; gap:6px; font-size:12.5px; color:var(--text-muted); margin-bottom:10px; }
			/* App Builder · Interactive Report control break (group by) */
			.ir-breakbar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:12px; }
			.ir-breakbar select{ width:auto; }
			.ir-break-label{ font-size:12px; color:var(--text-muted); }
			/* App Builder · List / Breadcrumb navigation regions */
			.ab-navlist{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; }
			.ab-navlist li a{ display:block; padding:9px 12px; border-radius:8px; color:var(--text); text-decoration:none; font-size:14px; }
			.ab-navlist li a:hover{ background:var(--bg); color:var(--red); }
			.ab-breadcrumb{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; font-size:13px; }
			.ab-breadcrumb a{ color:var(--text-muted); text-decoration:none; }
			.ab-breadcrumb a:hover{ color:var(--red); }
			.ab-bc-sep{ color:var(--text-faint); }
			/* App Builder · Cards region */
			.ab-cards{ display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:14px; }
			.ab-card{ border:1px solid var(--border); border-radius:12px; padding:14px 16px; background:var(--surface); display:flex; flex-direction:column; gap:10px; }
			.ab-card-title{ margin:0; font-size:15px; font-weight:600; color:var(--text); }
			.ab-card-fields{ margin:0; display:flex; flex-direction:column; gap:6px; }
			.ab-card-field{ display:flex; justify-content:space-between; gap:12px; font-size:13px; }
			.ab-card-field dt{ color:var(--text-muted); margin:0; }
			.ab-card-field dd{ margin:0; color:var(--text); text-align:right; word-break:break-word; }
			.ab-card-link{ align-self:flex-start; font-size:12px; padding:5px 10px; margin-top:2px; }
			/* App Builder · Calendar region */
			.ab-cal{ display:flex; flex-direction:column; gap:10px; }
			.ab-cal-head{ display:flex; align-items:center; gap:10px; }
			.ab-cal-head .btn{ font-size:12px; padding:5px 10px; }
			.ab-cal-month{ font-weight:600; font-size:15px; text-transform:capitalize; }
			.ab-cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:1px; background:var(--border); border:1px solid var(--border); border-radius:10px; overflow:hidden; }
			.ab-cal-wd{ background:var(--surface); padding:6px 8px; font-size:11px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.04em; text-align:center; }
			.ab-cal-day{ background:var(--surface); min-height:86px; padding:6px; display:flex; flex-direction:column; gap:3px; }
			.ab-cal-out{ background:var(--bg); }
			.ab-cal-out .ab-cal-num{ color:var(--text-faint); }
			.ab-cal-today .ab-cal-num{ background:var(--red); color:#fff; border-radius:50%; width:20px; height:20px; display:inline-flex; align-items:center; justify-content:center; }
			.ab-cal-num{ font-size:12px; color:var(--text-muted); }
			.ab-cal-ev{ display:block; font-size:11.5px; padding:2px 5px; border-radius:5px; background:color-mix(in srgb, var(--red) 14%, transparent); color:var(--text); text-decoration:none; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			a.ab-cal-ev:hover{ background:color-mix(in srgb, var(--red) 26%, transparent); }
			@media (max-width:700px){ .ab-cal-day{ min-height:60px; } .ab-cal-ev{ font-size:10.5px; } }
			/* App Builder · Badge List region */
			.ab-badges{ display:flex; flex-wrap:wrap; gap:8px; }
			.ab-badge{ display:inline-flex; align-items:center; gap:6px; background:var(--surface-alt); border:1px solid var(--border); border-radius:999px; padding:4px 12px; font-size:13px; color:var(--text); }
			.ab-badge-count{ background:var(--red); color:#fff; border-radius:999px; padding:0 7px; font-size:11.5px; font-weight:700; min-width:18px; text-align:center; }
			/* App Builder · región de componente propio del workspace.
			   Muestra el contrato resuelto, no la definición del componente:
			   el DSL que la interpreta llega en la fase siguiente. */
			.ab-custom{ display:flex; flex-direction:column; gap:12px; }
			.ab-custom-head{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
			.ab-custom-icon{ font-size:17px; color:var(--red); line-height:1; }
			.ab-custom-name{ font-weight:600; font-size:14.5px; color:var(--text); }
			.ab-custom-ver{ margin-left:auto; font-size:11.5px; color:var(--text-muted); background:var(--surface-alt); border:1px solid var(--border); border-radius:6px; padding:2px 8px; }
			.ab-custom-facts{ display:grid; grid-template-columns:auto 1fr; gap:5px 16px; margin:0; font-size:13px; }
			.ab-custom-facts dt{ color:var(--text-muted); }
			.ab-custom-facts dd{ margin:0; color:var(--text); }
			.ab-custom-rows{ width:100%; border-collapse:collapse; font-size:13px; }
			.ab-custom-rows th{ text-align:left; padding:7px 10px; color:var(--text-muted); font-size:11.5px; text-transform:uppercase; letter-spacing:.05em; border-bottom:1px solid var(--border); }
			.ab-custom-rows td{ padding:7px 10px; border-bottom:1px solid var(--border); color:var(--text); }
			.ab-custom-note{ margin:0; padding:9px 12px; font-size:12px; line-height:1.45; color:var(--text-muted); background:var(--surface-alt); border-left:2px solid var(--red); border-radius:0 8px 8px 0; }
			.ab-custom-error{ margin:0; padding:10px 12px; font-size:12.5px; line-height:1.5; color:var(--text); background:rgba(214,74,58,.10); border-left:2px solid var(--red); border-radius:0 8px 8px 0; }
			.ab-custom-error strong{ display:block; margin-bottom:3px; color:var(--red-light); }

			/* App Builder · consola de componentes propios */
			.ab-comp-editor{ display:grid; grid-template-columns:minmax(0,1fr) 320px; gap:16px; align-items:start; }
			.ab-comp-main{ display:flex; flex-direction:column; gap:16px; min-width:0; }
			.ab-comp-side{ display:flex; flex-direction:column; gap:16px; position:sticky; top:16px; }
			.ab-comp-actions{ display:flex; flex-direction:column; gap:9px; }
			.ab-comp-code{ width:100%; font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:12.5px;
			               line-height:1.6; background:var(--bg); border:1px solid var(--border); color:var(--text);
			               border-radius:8px; padding:12px; resize:vertical; tab-size:2; }
			.ab-comp-preview{ background:var(--surface-alt); border:1px solid var(--border); border-radius:10px; padding:14px; }
			.ab-comp-samplenote{ margin:9px 0 0; font-size:11.5px; color:var(--text-muted); }
			.ab-comp-errors{ background:rgba(214,74,58,.09); border-left:2px solid var(--red); border-radius:0 8px 8px 0; padding:11px 14px; }
			.ab-comp-errors-head{ margin:0 0 7px; font-size:12.5px; font-weight:600; color:var(--red-light); }
			.ab-comp-errors ul{ margin:0; padding-left:16px; display:flex; flex-direction:column; gap:5px; }
			.ab-comp-errors li{ font-size:12px; line-height:1.5; color:var(--text); font-family:ui-monospace,'SF Mono',Menlo,monospace; }
			.ab-comp-table{ width:100%; border-collapse:collapse; font-size:13px; }
			.ab-comp-table th{ text-align:left; padding:8px 10px; color:var(--text-muted); font-size:11px;
			                   text-transform:uppercase; letter-spacing:.05em; border-bottom:1px solid var(--border); }
			.ab-comp-table td{ padding:9px 10px; border-bottom:1px solid var(--border); vertical-align:middle; }
			.ab-comp-icon{ width:30px; font-size:16px; color:var(--red); text-align:center; }
			.ab-comp-name{ font-weight:600; color:var(--text); text-decoration:none; }
			.ab-comp-name:hover{ color:var(--red-light); }
			.ab-comp-slug{ display:block; font-size:11px; color:var(--text-muted); margin-top:2px; }
			.ab-comp-frozen{ align-self:center; font-size:11.5px; color:var(--text-muted);
			                 background:var(--surface-alt); border:1px solid var(--border);
			                 border-radius:6px; padding:5px 10px; }
			.ab-comp-stale{ color:#c9a227; border-color:rgba(201,162,39,.4); background:rgba(201,162,39,.10); }
			.ab-comp-chips{ display:flex; flex-wrap:wrap; gap:5px; }
			.ab-comp-chip{ font-size:11px; background:var(--surface-alt); border:1px solid var(--border);
			               border-radius:5px; padding:2px 7px; color:var(--text); }
			.ab-comp-vocab{ margin-bottom:12px; }
			.ab-comp-vocab h3{ margin:0 0 6px; font-size:11px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-muted); font-weight:600; }
			.ab-comp-versions{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; }
			.ab-comp-versions li{ display:flex; gap:9px; align-items:baseline; font-size:12px; }
			.ab-comp-vnum{ font-family:ui-monospace,'SF Mono',Menlo,monospace; font-weight:700; color:var(--text); }
			.ab-flash{ padding:10px 14px; border-radius:8px; font-size:13px; margin-bottom:14px;
			           background:rgba(63,163,77,.10); border-left:2px solid var(--green); color:var(--text); }
			.ab-flash.error{ background:rgba(214,74,58,.10); border-left-color:var(--red); }
			@media (max-width:1100px){ .ab-comp-editor{ grid-template-columns:1fr; } .ab-comp-side{ position:static; } }

			/* ── Vocabulario del lenguaje de componentes (dxc-*) ──────────────
			   Estas son las ÚNICAS clases que un componente propio puede pedir.
			   Se definen acá, con los tokens de la marca, por dos razones: que
			   un componente salga consistente con el design system por
			   construcción y no por disciplina, y que no quede atado a las
			   clases internas del builder, que se refactorizan sin aviso. */
			.dxc-root{ font-size:13.5px; color:var(--text); line-height:1.5; }
			/* Layout */
			.dxc-stack{ display:flex; flex-direction:column; gap:10px; }
			.dxc-row{ display:flex; flex-direction:row; align-items:center; gap:10px; }
			.dxc-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:10px; }
			.dxc-grid-2{ display:grid; grid-template-columns:repeat(2,1fr); gap:10px; }
			.dxc-grid-3{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
			.dxc-grid-4{ display:grid; grid-template-columns:repeat(4,1fr); gap:10px; }
			.dxc-wrap{ flex-wrap:wrap; }
			.dxc-fill{ flex:1 1 auto; min-width:0; }
			.dxc-between{ justify-content:space-between; }
			.dxc-center{ justify-content:center; align-items:center; }
			.dxc-end{ justify-content:flex-end; }
			.dxc-baseline{ align-items:baseline; }
			/* Espaciado */
			.dxc-gap-0{ gap:0; } .dxc-gap-1{ gap:5px; } .dxc-gap-2{ gap:10px; }
			.dxc-gap-3{ gap:16px; } .dxc-gap-4{ gap:24px; }
			.dxc-pad-0{ padding:0; } .dxc-pad-1{ padding:6px; }
			.dxc-pad-2{ padding:12px; } .dxc-pad-3{ padding:18px; }
			/* Superficies */
			.dxc-card{ background:var(--surface-alt); border:1px solid var(--border); border-radius:10px; padding:14px; }
			.dxc-panel{ background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:12px; }
			.dxc-tile{ background:var(--surface-alt); border:1px solid var(--border); border-radius:10px; padding:12px 14px; display:flex; flex-direction:column; gap:4px; }
			.dxc-divider{ height:1px; background:var(--border); border:0; margin:2px 0; }
			.dxc-badge{ display:inline-flex; align-items:center; gap:5px; background:var(--surface-alt); border:1px solid var(--border); border-radius:6px; padding:2px 8px; font-size:12px; }
			.dxc-pill{ display:inline-flex; align-items:center; gap:5px; background:var(--surface-alt); border:1px solid var(--border); border-radius:999px; padding:3px 11px; font-size:12px; }
			/* Tipografía */
			.dxc-title{ font-size:15px; font-weight:700; letter-spacing:-.01em; margin:0; }
			.dxc-subtitle{ font-size:13px; font-weight:600; color:var(--text-muted); margin:0; }
			.dxc-body{ font-size:13.5px; margin:0; }
			.dxc-caption{ font-size:11.5px; color:var(--text-muted); letter-spacing:.02em; }
			.dxc-metric{ font-size:26px; font-weight:700; line-height:1.05; letter-spacing:-.02em; }
			.dxc-mono{ font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:12.5px; font-variant-numeric:tabular-nums; }
			.dxc-bold{ font-weight:700; }
			.dxc-nowrap{ white-space:nowrap; }
			.dxc-truncate{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; }
			.dxc-right{ text-align:right; }
			.dxc-uppercase{ text-transform:uppercase; letter-spacing:.05em; font-size:11px; }
			/* Color semántico */
			.dxc-muted{ color:var(--text-muted); }
			.dxc-accent{ color:var(--red-light); }
			.dxc-positive{ color:var(--green); }
			.dxc-negative{ color:var(--red-light); }
			.dxc-warning{ color:#c9a227; }
			/* Tablas */
			.dxc-table{ width:100%; border-collapse:collapse; font-size:13px; }
			.dxc-table th{ text-align:left; padding:7px 10px; color:var(--text-muted); font-size:11px; text-transform:uppercase; letter-spacing:.05em; border-bottom:1px solid var(--border); }
			.dxc-table td{ padding:7px 10px; border-bottom:1px solid var(--border); }
			.dxc-table-compact th, .dxc-table-compact td{ padding:4px 8px; }
			/* App Builder · Timeline region */
			.ab-timeline{ list-style:none; margin:0; padding:0 0 0 12px; border-left:2px solid var(--border); display:flex; flex-direction:column; gap:16px; }
			.ab-tl-item{ position:relative; display:flex; gap:14px; }
			.ab-tl-item::before{ content:""; position:absolute; left:-19px; top:4px; width:10px; height:10px; border-radius:50%; background:var(--red); border:2px solid var(--surface); }
			.ab-tl-time{ flex:0 0 auto; font-size:12px; color:var(--text-muted); min-width:96px; }
			.ab-tl-body{ display:flex; flex-direction:column; gap:2px; }
			.ab-tl-title{ font-weight:600; font-size:14px; color:var(--text); }
			.ab-tl-detail{ font-size:12.5px; color:var(--text-muted); }
			.ab-tl-detail em{ color:var(--text-faint); font-style:normal; }
			/* App Builder · Tree region */
			.ab-tree, .ab-tree ul{ list-style:none; margin:0; padding-left:16px; }
			.ab-tree{ padding-left:2px; font-size:13.5px; }
			.ab-tree-node{ margin:3px 0; }
			.ab-tree summary{ cursor:pointer; color:var(--text); }
			.ab-tree summary:hover{ color:var(--red); }
			.ab-tree-leaf{ color:var(--text-muted); }
			.ab-tree-leaf::before{ content:"·"; margin-right:6px; color:var(--text-faint); }
			/* App Builder · HTML Content region */
			.ab-html-content{ font-size:13.5px; color:var(--text); line-height:1.6; }
			.ab-html-content :where(h1,h2,h3){ margin:0 0 8px; }
			.ab-html-content :where(p,ul,ol,table){ margin:0 0 10px; }
			/* App Builder · Faceted Search region */
			.ab-faceted{ display:flex; gap:18px; align-items:flex-start; }
			.ab-facets{ flex:0 0 200px; display:flex; flex-direction:column; gap:14px; }
			.ab-facet-group{ background:var(--surface-alt); border:1px solid var(--border); border-radius:10px; padding:10px 12px; }
			.ab-facet-head{ display:flex; justify-content:space-between; align-items:center; font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:var(--text-muted); font-weight:700; margin-bottom:6px; }
			.ab-facet-clear{ font-size:10.5px; text-transform:none; letter-spacing:0; color:var(--red); text-decoration:none; }
			.ab-facet-values{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; }
			.ab-facet-val{ display:flex; justify-content:space-between; gap:8px; align-items:center; padding:4px 7px; border-radius:6px; font-size:12.5px; color:var(--text); text-decoration:none; }
			.ab-facet-val:hover{ background:var(--surface); }
			.ab-facet-val.on{ background:var(--red); color:#fff; }
			.ab-facet-label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.ab-facet-count{ flex:0 0 auto; font-size:11px; color:var(--text-muted); }
			.ab-facet-val.on .ab-facet-count{ color:#fff; }
			.ab-facet-results{ flex:1 1 auto; min-width:0; }
			@media (max-width:700px){ .ab-faceted{ flex-direction:column; } .ab-facets{ flex-basis:auto; width:100%; } }
			/* App Builder · Map region */
			.ab-map{ border:1px solid var(--border); border-radius:10px; background:var(--surface-alt); overflow:hidden; }
			.ab-map-svg{ display:block; width:100%; height:auto; background:linear-gradient(180deg, color-mix(in srgb, var(--red) 5%, var(--surface)) 0%, var(--surface) 100%); }
			.ab-map-pt{ fill:var(--red); stroke:#fff; stroke-width:1.5; }
			a:hover > .ab-map-pt{ fill:#fff; stroke:var(--red); }
			.ab-map-label{ font-size:10px; fill:var(--text-muted); }
			/* App Builder · Tabs region */
			.ab-tabs-bar{ display:flex; flex-wrap:wrap; gap:2px; border-bottom:1px solid var(--border); margin-bottom:12px; }
			.ab-tab{ background:none; border:none; border-bottom:2px solid transparent; padding:7px 14px; font-size:13px; color:var(--text-muted); cursor:pointer; }
			.ab-tab:hover{ color:var(--text); }
			.ab-tab.on{ color:var(--text); border-bottom-color:var(--red); font-weight:600; }
			.ab-tab-panel{ font-size:13.5px; color:var(--text); line-height:1.6; }
			/* App Builder · Region Display Selector */
			.ab-rds{ display:flex; flex-wrap:wrap; gap:2px; }
			.ab-rds-tab{ background:var(--surface-alt); border:1px solid var(--border); border-radius:8px; padding:7px 14px; font-size:13px; color:var(--text-muted); cursor:pointer; }
			.ab-rds-tab:hover{ color:var(--text); border-color:var(--text-muted); }
			.ab-rds-tab.on{ background:var(--red); border-color:var(--red); color:#fff; font-weight:600; }
			/* App Builder · opción de páginas de administración de APEX */
			.ab-apexpages{ margin-top:14px; border:1px solid var(--border); border-radius:10px; padding:12px 14px; background:var(--bg); }
			.ab-apexpages-row{ display:flex; align-items:flex-start; gap:9px; font-size:13.5px; cursor:pointer; }
			.ab-apexpages-row input{ width:auto; margin-top:2px; }
			.ab-apexpages-help{ margin:8px 0 0; font-size:12.5px; color:var(--text-muted); line-height:1.55; }
			.ab-apexpages-help code{ font-size:11.5px; }
			/* Historial de imports */
			.imp-ok{ color:#3FB873; font-weight:700; margin-right:4px; }
			.imp-bad{ color:#e06e63; font-weight:700; margin-right:4px; }
			.imp-counts{ display:flex; flex-wrap:wrap; gap:6px; margin-top:5px; }
			.imp-c{ font-size:11px; padding:2px 7px; border-radius:20px; border:1px solid var(--border); color:var(--text-muted); }
			.imp-c-auto{ border-color:color-mix(in srgb,#3FB873 45%,transparent); color:#3FB873; }
			.imp-c-rev{ border-color:color-mix(in srgb,#d9822b 45%,transparent); color:#d9822b; }
			.imp-c-man{ border-color:color-mix(in srgb,#e06e63 45%,transparent); color:#e06e63; }
			.imp-notes{ display:flex; flex-direction:column; gap:5px; padding:10px 4px; }
			.imp-note{ display:flex; align-items:flex-start; gap:9px; font-size:12.5px; line-height:1.5; }
			.imp-sev{ flex:0 0 auto; font-size:10px; letter-spacing:.05em; padding:2px 7px; border-radius:20px; font-weight:700; }
			.imp-sev-auto{ background:color-mix(in srgb,#3FB873 16%,transparent); color:#3FB873; }
			.imp-sev-rev{ background:color-mix(in srgb,#d9822b 16%,transparent); color:#d9822b; }
			.imp-sev-man{ background:color-mix(in srgb,#e06e63 16%,transparent); color:#e06e63; }
			.imp-extra{ margin:8px 0 0; font-size:12px; color:var(--text-muted); }
			.imp-row{ cursor:pointer; }
			.imp-row:hover{ background:var(--bg); }
			.imp-meta{ display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:8px 18px; margin:0 0 12px; font-size:12.5px; }
			.imp-meta > div{ display:flex; flex-direction:column; gap:2px; }
			.imp-meta span:first-child{ font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-faint); }
			.imp-toolbar{ display:flex; flex-wrap:wrap; gap:10px; justify-content:space-between; align-items:center; margin-top:14px; padding-top:12px; border-top:1px solid var(--border); }
			.imp-filters{ display:flex; flex-wrap:wrap; gap:6px; }
			.imp-filters .secondary{ font-size:11px; padding:5px 10px; }
			.imp-f-on{ border-color:var(--red) !important; color:var(--red) !important; }
			.imp-downloads{ display:flex; gap:6px; }
			.imp-downloads .btn{ font-size:11px; padding:5px 10px; }
			.imp-notes-scroll{ max-height:46vh; overflow-y:auto; margin-top:6px; }
			/* App Builder · Roles */
			.ab-role-card{ border:1px solid var(--border); border-radius:10px; padding:12px 14px; margin-bottom:10px; }
			.ab-role-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
			.ab-role-members{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:8px; }
			.ir-break-head td{ font-weight:700; color:var(--red); background:color-mix(in srgb, var(--red) 8%, transparent); border-top:2px solid var(--border); letter-spacing:.01em; }
			.ir-break-sub td{ background:color-mix(in srgb, var(--red) 4%, transparent); border-bottom:2px solid var(--border); }
			/* App Builder · Interactive Report conditional highlighting */
			.ir-hlbar{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; margin-bottom:12px; }
			.ir-hl-label{ font-size:12px; color:var(--text-muted); }
			.ir-addhl{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
			.ir-addhl select{ width:auto; flex:0 0 auto; }
			.ir-addhl .ir-filter-val{ flex:0 0 120px; }
			/* Row highlight palette + matching chip tints (readable on the dark UI). */
			.ir-hl-amber td{ background:color-mix(in srgb, #d9a441 20%, transparent); }
			.ir-hl-green td{ background:color-mix(in srgb, #4a9d5b 20%, transparent); }
			.ir-hl-red   td{ background:color-mix(in srgb, #c0483b 22%, transparent); }
			.ir-hl-blue  td{ background:color-mix(in srgb, #3f7cc0 22%, transparent); }
			.ir-hl-gray  td{ background:color-mix(in srgb, #888a8b 22%, transparent); }
			span.ir-hl-amber{ border-color:#d9a441; } span.ir-hl-amber::before{ content:""; width:9px; height:9px; border-radius:2px; background:#d9a441; display:inline-block; margin-right:2px; }
			span.ir-hl-green{ border-color:#4a9d5b; } span.ir-hl-green::before{ content:""; width:9px; height:9px; border-radius:2px; background:#4a9d5b; display:inline-block; margin-right:2px; }
			span.ir-hl-red{ border-color:#c0483b; } span.ir-hl-red::before{ content:""; width:9px; height:9px; border-radius:2px; background:#c0483b; display:inline-block; margin-right:2px; }
			span.ir-hl-blue{ border-color:#3f7cc0; } span.ir-hl-blue::before{ content:""; width:9px; height:9px; border-radius:2px; background:#3f7cc0; display:inline-block; margin-right:2px; }
			span.ir-hl-gray{ border-color:#888a8b; } span.ir-hl-gray::before{ content:""; width:9px; height:9px; border-radius:2px; background:#888a8b; display:inline-block; margin-right:2px; }

			/* App Builder · Interactive Grid (editable) */
			.grid-table input[type=text], .grid-table input[type=number], .grid-table input[type=date]{ padding:5px 8px; font-size:12px; min-width:90px; margin:0; }
			.grid-table td, .grid-table th{ padding:6px 8px; }
			.grid-del{ text-align:center; white-space:nowrap; }
			.grid-newrow{ background:rgba(63,184,115,.06); }
			.grid-newtag{ font-size:10px; color:var(--green); text-transform:uppercase; letter-spacing:.05em; }
			.grid-ro{ color:var(--text-muted); font-size:12px; }

			/* App Builder · Chart + Data Load */
			.ab-chart-wrap{ width:100%; position:relative; }
			.ab-chart{ width:100%; max-width:660px; height:auto; }
			/* Interactive line chart (JS-upgraded): axis, crosshair, tooltip, brush.
			   JS sizes the SVG to the region's content box (width AND height) so the
			   whole chart — axes included — always renders with no scroll. */
			.ab-chart-live{ display:block; max-width:100%; touch-action:none; }
			.ab-chart-grid{ stroke:color-mix(in srgb, var(--border) 55%, transparent); stroke-width:1; shape-rendering:crispEdges; }
			.ab-chart-axis-label{ fill:var(--text-muted); font-size:10px; font-variant-numeric:tabular-nums; }
			.ab-chart-line{ fill:none; stroke:var(--red); stroke-width:2.5; stroke-linejoin:round; stroke-linecap:round; }
			.ab-chart-area{ opacity:.9; }
			.ab-chart-bar{ fill:var(--red); opacity:.85; transition:opacity .1s; }
			.ab-chart-bar.is-hi{ opacity:1; }
			.ab-chart-slice{ transition:opacity .12s; cursor:pointer; stroke:var(--surface); stroke-width:1.5; }
			.ab-chart-slice.is-dim{ opacity:.4; }
			.ab-chart-legend{ fill:var(--text); font-size:11px; }
			.ab-chart-center{ fill:var(--text); font-size:17px; font-weight:700; }
			.ab-chart-center-sub{ fill:var(--text-muted); font-size:9px; text-transform:uppercase; letter-spacing:.08em; }
			.ab-chart-cursor{ transition:opacity .1s; }
			.ab-chart-cross{ stroke:var(--text-muted); stroke-width:1; stroke-dasharray:4 4; pointer-events:none; }
			.ab-chart-focus{ fill:var(--red); stroke:var(--surface); stroke-width:2.5; pointer-events:none; }
			.ab-chart-brush{ fill:color-mix(in srgb, var(--red) 16%, transparent); stroke:color-mix(in srgb, var(--red) 55%, transparent); stroke-width:1; pointer-events:none; }
			.ab-chart-hit{ cursor:crosshair; }
			.ab-chart-tip{ position:absolute; z-index:6; pointer-events:none; transform:translate(-50%,-135%); background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:4px 9px; font-size:11px; color:var(--text); box-shadow:0 6px 18px rgba(0,0,0,.35); white-space:nowrap; opacity:0; transition:opacity .08s; display:flex; gap:8px; align-items:center; }
			.ab-chart-tip .ab-chart-tip-l{ color:var(--text-muted); }
			.ab-chart-tip b{ color:var(--red); font-variant-numeric:tabular-nums; }
			.ab-chart-reset{ position:absolute; top:6px; right:6px; z-index:6; font-size:11px; padding:3px 10px; border-radius:7px; border:1px solid var(--border); background:var(--surface); color:var(--text-muted); cursor:pointer; }
			.ab-chart-reset:hover{ color:var(--text); border-color:var(--red); }
			.app-runtime-ok{ background:rgba(63,184,115,.14); border:1px solid var(--green); color:var(--green); border-radius:8px; padding:9px 14px; font-size:12.5px; margin-bottom:4px; }
			.app-runtime-or{ font-size:11px; color:var(--text-muted); text-align:center; margin:2px 0; }

			/* App Builder · runtime navigation menu (shared component) */
			.app-runtime-nav{ display:flex; flex-wrap:wrap; gap:4px; padding:8px 26px; background:var(--surface); border-bottom:1px solid var(--border); }
			.app-runtime-nav a{ font-size:12.5px; color:var(--text-muted); text-decoration:none; padding:6px 12px; border-radius:7px; }
			.app-runtime-nav a:hover{ background:var(--surface-alt); color:var(--text); }
			.app-runtime-nav a.active{ background:var(--red); color:#fff; }

			/* App Builder · drag-and-drop reorder (page designer) */
			.ab-drag{ color:var(--text-faint); font-size:14px; line-height:1; }
			.ab-drag-handle{ cursor:grab; padding:0 4px; user-select:none; }
			.ab-drag-handle:active{ cursor:grabbing; }
			.ab-drag-ghost{ opacity:.45; background:var(--surface-alt); border:1px dashed var(--red); }

			/* App Builder · Page Designer object tree + layout panes */
			.ab-tree{ max-height:calc(100vh - 120px); }
			.ab-tree-count{ display:inline-block; min-width:16px; text-align:center; background:var(--surface-alt); color:var(--text-muted); border-radius:10px; padding:0 6px; font-size:10px; margin-left:5px; }
			.ab-region-icon{ color:var(--red); font-size:13px; }
			.ab-designer .rest-main{ min-width:0; }
			.tpl-card{ scroll-margin-top:78px; transition:box-shadow .2s ease; }
			.tpl-card:target{ box-shadow:0 0 0 2px var(--red); }

			/* App Builder · free-form layout canvas (Photoshop-like: drag anywhere,
			   resize width/height, bounded by the page, no overlap). */
			.ab-free-scroll{ overflow-x:auto; padding-bottom:6px; }
			/* The page has an explicit width; a handle on its right edge resizes it. */
			.ab-page-frame{ position:relative; display:inline-block; }
			.ab-page-rz{ position:absolute; top:0; bottom:0; right:-13px; width:11px; cursor:ew-resize; z-index:8; touch-action:none; }
			.ab-page-rz::after{ content:""; position:absolute; top:50%; right:3px; transform:translateY(-50%); width:4px; height:46px; border-radius:4px; background:var(--border); }
			.ab-page-rz:hover::after, .ab-free-canvas.ab-resizing + .ab-page-rz::after{ background:var(--red); }
			.ab-free-canvas{ position:relative; margin:0; background:var(--bg); border:1px solid var(--border); border-radius:12px; background-image:radial-gradient(color-mix(in srgb, var(--border) 55%, transparent) 1px, transparent 1px); background-size:18px 18px; }
			.ab-free-region{ position:absolute; box-sizing:border-box; background:var(--surface-alt); border:1px solid var(--border); border-radius:9px; overflow:hidden; }
			.ab-free-region.ab-dragging, .ab-free-region.ab-resizing{ box-shadow:0 0 0 2px var(--red); z-index:6; }
			.ab-free-head{ position:relative; z-index:3; display:flex; align-items:center; gap:8px; font-size:12px; padding:6px 9px; background:var(--surface); border-bottom:1px solid var(--border); cursor:grab; user-select:none; touch-action:none; }
			.ab-free-head:active{ cursor:grabbing; }
			.ab-free-body{ position:absolute; left:0; right:0; top:33px; bottom:0; padding:9px 11px; overflow:hidden; pointer-events:none; z-index:0; opacity:.85; }
			.ab-free-body .ab-skel{ margin-top:0; }
			.ab-free-itemlayer{ position:absolute; left:0; right:0; top:33px; bottom:0; z-index:2; cursor:grab; }
			.ab-free-region.ab-dragging, .ab-free-region.ab-dragging .ab-free-itemlayer{ cursor:grabbing; }
			.ab-free-item{ position:absolute; box-sizing:border-box; display:flex; align-items:center; gap:4px; background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:0 10px; font-size:11.5px; cursor:grab; white-space:nowrap; overflow:hidden; user-select:none; touch-action:none; }
			.ab-free-item:active{ cursor:grabbing; }
			/* An item lifted out of its region to be dragged across the canvas. */
			.ab-free-item.ab-lifting{ z-index:100; opacity:.95; box-shadow:0 8px 24px rgba(0,0,0,.45); }
			.ab-free-region.ab-drop-target{ box-shadow:0 0 0 2px var(--red) inset; }
			.ab-free-item-label{ overflow:hidden; text-overflow:ellipsis; pointer-events:none; }
			/* Item resize handles fill the edges (no header offset like regions). */
			.ab-free-item > .ab-rz-e{ top:0; bottom:0; right:0; width:8px; }
			.ab-free-item > .ab-rz-s{ left:0; right:0; bottom:0; height:8px; }
			.ab-free-item > .ab-rz-se{ right:0; bottom:0; width:12px; height:12px; }
			/* Resize handles are inert until the object is selected, so an item and
			   its region never fight for the same edge (click selects; then resize). */
			.ab-rz{ position:absolute; z-index:5; touch-action:none; opacity:0; pointer-events:none; }
			.ab-free-region.ab-selected > .ab-rz, .ab-free-item.ab-selected > .ab-rz{ opacity:1; pointer-events:auto; }
			.ab-rz-e{ top:33px; right:0; bottom:12px; width:9px; cursor:ew-resize; }
			.ab-rz-s{ left:12px; right:12px; bottom:0; height:9px; cursor:ns-resize; }
			.ab-rz-se{ right:0; bottom:0; width:16px; height:16px; cursor:nwse-resize; }
			.ab-rz-se::after{ content:""; position:absolute; right:3px; bottom:3px; width:8px; height:8px; border-right:2px solid var(--red); border-bottom:2px solid var(--red); }
			.ab-free-region.ab-selected > .ab-rz-e, .ab-free-region.ab-selected > .ab-rz-s,
			.ab-free-item.ab-selected > .ab-rz-e, .ab-free-item.ab-selected > .ab-rz-s{ background:color-mix(in srgb, var(--red) 22%, transparent); }
			.ab-free-global{ margin-top:12px; border:1px dashed var(--border); border-radius:9px; padding:9px 11px; }
			.ab-free-global-head{ font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-muted); margin-bottom:8px; }
			.ab-free-global-list{ display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
			/* Full-screen layout mirror (own tab): use the whole window width. */
			.ab-full{ min-height:100vh; display:flex; flex-direction:column; background:var(--bg); }
			.ab-full-top{ position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:14px; flex-wrap:wrap; padding:12px 20px; background:var(--surface); border-bottom:1px solid var(--border); }
			.ab-full-title{ display:flex; align-items:center; gap:10px; font-size:13px; color:var(--text); }
			.ab-full-title svg, .ab-full-title img{ height:22px; width:auto; }
			.ab-full-actions{ display:flex; align-items:center; gap:10px; margin-left:auto; }
			.ab-full-canvas{ flex:1; padding:20px; }
			.ab-full-canvas .ab-free-scroll{ overflow:visible; }
			.ab-full-canvas .ab-free-canvas{ margin:0 auto; }
			.ab-resize-hint{ color:var(--red); }
			/* Smart alignment guides (snap lines), spacing hints, live HUD, selection. */
			.ab-guide-layer{ position:absolute; inset:0; pointer-events:none; z-index:40; }
			.ab-guide{ position:absolute; }
			.ab-guide-v{ width:1px; background:var(--red); }
			.ab-guide-h{ height:1px; background:var(--red); }
			.ab-guide-center{ background:repeating-linear-gradient(var(--dir,to bottom), color-mix(in srgb, var(--red) 90%, #fff), color-mix(in srgb, var(--red) 90%, #fff) 4px, transparent 4px, transparent 8px); }
			.ab-guide-v.ab-guide-center{ width:2px; --dir:to bottom; }
			.ab-guide-h.ab-guide-center{ height:2px; --dir:to right; }
			.ab-guide-gap{ background:color-mix(in srgb, var(--red) 65%, transparent); border-radius:1px; }
			.ab-hud{ position:absolute; z-index:42; background:var(--red); color:#fff; font-size:10px; line-height:1.5; padding:1px 7px; border-radius:6px; pointer-events:none; font-variant-numeric:tabular-nums; white-space:nowrap; box-shadow:0 1px 4px rgba(0,0,0,.3); }
			.ab-free-region.ab-selected, .ab-free-item.ab-selected{ outline:2px solid var(--red); outline-offset:1px; }
			/* Wireframe silhouettes of a region's content (no real data). */
			.ab-skel{ margin-top:8px; pointer-events:none; }
			.ab-skel-table{ display:flex; flex-direction:column; gap:5px; }
			.ab-skel-row{ height:9px; border-radius:3px; background:color-mix(in srgb, var(--text-faint) 22%, transparent); }
			.ab-skel-row.ab-skel-hd{ height:12px; background:color-mix(in srgb, var(--red) 30%, transparent); }
			.ab-skel-form{ display:flex; flex-direction:column; gap:7px; }
			.ab-skel-field{ display:flex; flex-direction:column; gap:3px; }
			.ab-skel-lab{ width:38%; height:7px; border-radius:3px; background:color-mix(in srgb, var(--text-faint) 30%, transparent); }
			.ab-skel-in{ height:15px; border-radius:4px; background:var(--surface); border:1px solid var(--border); }
			.ab-skel-chart{ display:flex; align-items:flex-end; gap:8px; height:80px; padding-top:4px; }
			.ab-skel-bar{ flex:1; border-radius:3px 3px 0 0; background:color-mix(in srgb, var(--red) 34%, transparent); }
			.ab-skel-drop{ display:flex; align-items:center; justify-content:center; height:60px; border:1px dashed var(--border); border-radius:7px; color:var(--text-faint); font-size:12px; background:var(--surface); }
			.ab-block-type{ font-weight:700; text-transform:uppercase; font-size:10.5px; letter-spacing:.06em; color:var(--text-muted); }
			.ab-block-title{ color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.ab-block-jump{ margin-left:auto; font-size:10.5px; color:var(--text-muted); text-decoration:none; }
			.ab-block-jump:hover{ color:var(--red); }
			.ab-chip{ display:inline-flex; align-items:center; gap:4px; background:var(--bg); border:1px solid var(--border); border-radius:14px; padding:3px 11px; font-size:11.5px; white-space:nowrap; }
			.ab-chip-mini{ color:var(--red); }
			.ab-zone-hint{ font-size:10.5px; color:var(--text-faint); font-style:italic; }

			/* ── dX Bot ──────────────────────────────────────────────────────
			   The assistant panel. It keeps the brand tokens of the rest of
			   the console but breathes more than a data screen does: larger
			   type, rounder corners, more air. A chat is read, not scanned,
			   so it is laid out like a product page rather than a grid. */
			.bot{ max-width:960px; margin:0 auto; }

			/* Gated state: no key, no plan. The panel is visible on purpose --
			   showing what is behind the door sells it better than a 403. */
			.bot-hero{ text-align:center; padding:clamp(38px,7vw,86px) 20px clamp(30px,4vw,52px); }
			.bot-kicker{ font-size:11px; font-weight:700; letter-spacing:.18em; text-transform:uppercase; color:var(--red); }
			.bot-title{ font-size:clamp(44px,8vw,86px); font-weight:700; letter-spacing:-.04em; line-height:1.02; margin:18px 0 0; background:linear-gradient(178deg,#ffffff 6%,#cfd0c9 54%,#8e9089 100%); -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; }
			.bot-tag{ font-size:clamp(15px,2vw,20px); color:var(--text-muted); margin:18px auto 0; max-width:46ch; line-height:1.5; letter-spacing:-.008em; }

			.bot-doors{ display:grid; grid-template-columns:repeat(2,1fr); gap:16px; margin-top:clamp(30px,4vw,48px); }
			@media (max-width:760px){ .bot-doors{ grid-template-columns:1fr; } }
			.bot-door{ background:var(--surface); border:1px solid var(--border); border-radius:20px; padding:clamp(22px,3vw,32px); display:flex; flex-direction:column; text-align:left; }
			.bot-door.is-primary{ border-color:color-mix(in srgb, var(--red) 55%, transparent); background:linear-gradient(168deg,color-mix(in srgb, var(--red) 13%, transparent),var(--surface) 58%); }
			.bot-door h3{ font-size:19px; font-weight:700; letter-spacing:-.02em; margin:0 0 9px; color:var(--text); }
			.bot-door p{ font-size:14px; line-height:1.6; color:var(--text-muted); margin:0 0 22px; }
			.bot-door .bot-door-k{ font-size:10.5px; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--text-faint); margin-bottom:13px; }
			.bot-door.is-primary .bot-door-k{ color:var(--red-light); }
			.bot-door .bot-door-cta{ margin-top:auto; }
			.bot-door .bot-door-cta .btn,.bot-door .bot-door-cta button{ width:100%; }

			/* Access bar: which key is paying, and how deep it should think. */
			.bot-bar{ display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:space-between; padding:14px 18px; background:var(--surface); border:1px solid var(--border); border-radius:16px; }
			.bot-src{ display:inline-flex; align-items:center; gap:9px; font-size:12.5px; color:var(--text-muted); }
			.bot-src .bot-dot{ width:7px; height:7px; border-radius:50%; background:var(--green); flex-shrink:0; }
			.bot-src.is-blocked .bot-dot{ background:var(--red); }
			.bot-src code{ font-size:12px; color:var(--text); background:var(--bg); border:1px solid var(--border); border-radius:6px; padding:2px 8px; }

			/* Expandir a una ventana propia. Mismo gesto y mismo glifo que el
			   de las consolas de código, para que se reconozca sin explicarlo. */
			.bot-expand-btn,.bot-tool-btn{ display:inline-flex; align-items:center; justify-content:center; min-width:30px; height:30px; padding:0 8px; gap:4px; white-space:nowrap; padding:0; font-size:13px; line-height:1; background:transparent; color:var(--text-muted); border:1px solid var(--border); border-radius:8px; cursor:pointer; }
			.bot-expand-btn:hover,.bot-tool-btn:hover{ color:#fff; border-color:var(--text-muted); filter:none; }

			/* La ventana espejo: el panel solo, sin sidebar, ocupando todo. */
			.bot-expanded{ display:flex; flex-direction:column; height:100vh; }
			.bot-expanded-bar{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 22px; border-bottom:1px solid var(--border); flex-shrink:0; }
			.bot-expanded-title{ display:inline-flex; align-items:center; gap:11px; font-size:13.5px; font-weight:700; }
			.bot-expanded-title .brand-logo{ height:22px; }
			.bot-expanded-main{ flex:1; min-height:0; overflow-y:auto; padding:22px; max-width:1100px; width:100%; margin:0 auto; }
			/* Con toda la ventana disponible el hilo puede respirar más. */
			.bot-expanded .bot-thread{ max-height:none; }

			/* Lo que dice mientras trabaja. Es andamiaje: se ve, se reemplaza
			   por la respuesta y no queda en el hilo. */
			.bot-note{ align-self:flex-start; max-width:80%; font-size:13px; line-height:1.55; color:var(--text-faint); font-style:italic; padding:2px 4px; }

			/* The two segmented controls, grouped so they wrap together instead
			   of one of them stranding on its own line. */
			.bot-controls{ display:flex; flex-wrap:wrap; gap:8px; align-items:center; }

			/* Segmented controls: how deep it thinks, how long it answers. */
			.bot-seg{ display:inline-flex; background:var(--bg); border:1px solid var(--border); border-radius:99px; padding:3px; gap:2px; }
			.bot-seg button{ background:transparent; color:var(--text-muted); border-radius:99px; padding:6px 15px; font-size:11px; letter-spacing:.04em; text-transform:none; font-weight:600; }
			.bot-seg button:hover{ color:#fff; filter:none; }
			.bot-seg button.is-on{ background:var(--red); color:#fff; }

			/* Consumption. A normal API key exposes no balance endpoint, so
			   every figure here is our own accounting of the usage blocks. */
			.bot-meters{ display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--border); border:1px solid var(--border); border-radius:16px; overflow:hidden; margin-top:14px; }
			@media (max-width:760px){ .bot-meters{ grid-template-columns:repeat(2,1fr); } }
			.bot-meter{ background:var(--surface); padding:16px 18px; }
			.bot-meter .bot-m-v{ font-size:23px; font-weight:700; letter-spacing:-.03em; color:var(--text); font-variant-numeric:tabular-nums; }
			.bot-meter .bot-m-k{ font-size:10.5px; letter-spacing:.09em; text-transform:uppercase; color:var(--text-faint); margin-top:6px; }

			.bot-quota{ margin-top:14px; padding:16px 18px; background:var(--surface); border:1px solid var(--border); border-radius:16px; }
			.bot-quota-head{ display:flex; justify-content:space-between; align-items:baseline; gap:12px; font-size:12.5px; color:var(--text-muted); margin-bottom:11px; }
			.bot-quota-head b{ color:var(--text); font-variant-numeric:tabular-nums; }
			.bot-track{ height:6px; border-radius:99px; background:var(--bg); overflow:hidden; }
			.bot-fill{ height:100%; border-radius:99px; background:linear-gradient(90deg,var(--red),var(--red-light)); transition:width .5s cubic-bezier(.22,.61,.36,1); }
			.bot-fill.is-full{ background:var(--red); }

			/* Thread + composer. */
			.bot-thread{ margin-top:16px; display:flex; flex-direction:column; gap:20px; min-height:190px; padding:22px; background:var(--surface); border:1px solid var(--border); border-radius:20px; }
			.bot-empty{ margin:auto; text-align:center; color:var(--text-faint); font-size:13.5px; line-height:1.6; max-width:38ch; }
			/* Anchos.
			   Las dos partes van en burbuja, pero no simétricas. El mensaje de
			   la persona se ajusta a su texto (frases cortas). La respuesta
			   usa un ancho fijo y generoso en lugar de encogerse hasta su
			   contenido: así una tabla ancha y una línea de diez palabras
			   quedan en una caja del mismo tamaño, sin el borde dentado que
			   dejaba el ajuste-al-contenido. El contenedor no desaparece --
			   solo deja de cambiar de ancho según lo que haya adentro. */
			.bot-msg{ font-size:14.5px; line-height:1.6; word-break:break-word; padding:12px 16px; border-radius:16px; }
			.bot-msg.is-user{ align-self:flex-end; max-width:72%; border-radius:16px 16px 4px 16px; background:var(--red-soft); border:1px solid color-mix(in srgb, var(--red) 34%, transparent); white-space:pre-wrap; }
			.bot-msg.is-bot{ align-self:flex-start; width:100%; max-width:min(56%, 760px); background:var(--surface-alt); border:1px solid var(--border); }
			/* Markdown renderizado dentro de una burbuja.
			   Las tablas y los identificadores siguen el mismo lenguaje visual
			   que la grilla de SQL Commands: encabezado en versalitas sobre
			   surface-alt, filas separadas por una línea, y todo lo que es un
			   nombre de objeto en la misma monoespaciada que usa el Object
			   Browser. Una respuesta sobre tablas y columnas se lee como el
			   resto de la plataforma en vez de como un chat aparte. */
			.bot-md > :first-child{ margin-top:0; }
			.bot-md > :last-child{ margin-bottom:0; }
			.bot-md p{ margin:0 0 10px; }
			.bot-md ul,.bot-md ol{ margin:0 0 10px; padding-left:20px; }
			.bot-md li{ margin:3px 0; }
			.bot-md li::marker{ color:var(--text-faint); }
			.bot-md strong{ font-weight:700; color:#fff; }
			.bot-md em{ font-style:italic; }

			/* Nombres de tablas, columnas y aplicaciones: la misma
			   monoespaciada de .objsearch-name y .objdetail-col-name. */
			.bot-md code{ font-family:ui-monospace,'SF Mono',Menlo,monospace; font-size:12.5px; background:var(--bg); border:1px solid var(--border); border-radius:4px; padding:1px 6px; color:var(--text); }

			/* Grilla: mismo tratamiento que la de resultados, encerrada en su
			   propio panel para que se lea como una tabla de datos y no como
			   parte del párrafo. Scrollea adentro de la burbuja, así que una
			   comparación ancha no empuja el ancho del hilo. */
			.bot-md table{ display:block; width:max-content; max-width:100%; overflow-x:auto; margin:0 0 10px; border:1px solid var(--border); border-radius:8px; border-collapse:separate; border-spacing:0; }
			.bot-md thead th{ position:sticky; top:0; z-index:1; background:var(--surface-alt); color:var(--text-muted); font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.06em; }
			.bot-md th,.bot-md td{ padding:9px 14px; font-size:13px; text-align:left; white-space:nowrap; border-bottom:1px solid var(--border); }
			/* Las celdas numéricas se leen mejor alineadas por el dígito. */
			.bot-md td{ font-variant-numeric:tabular-nums; }
			.bot-md tbody tr:last-child td{ border-bottom:none; }
			.bot-md tbody tr:hover td{ background:color-mix(in srgb, var(--surface-alt) 55%, transparent); }
			/* Un identificador dentro de una celda no lleva su propia caja: en
			   una grilla ya se entiende que es un dato. */
			.bot-md td code,.bot-md th code{ background:transparent; border:none; padding:0; font-size:12.5px; }

			.bot-md a{ color:var(--red-light); border-bottom:1px solid currentColor; }

			.bot-msg.is-error{ align-self:flex-start; width:100%; max-width:min(56%, 760px); background:var(--red-soft); border:1px solid color-mix(in srgb, var(--red) 40%, transparent); color:var(--text); }
			.bot-msg.is-sys{ align-self:center; background:transparent; border:1px dashed var(--border); color:var(--text-muted); font-size:13px; text-align:center; }

			.bot-composer{ margin-top:12px; display:flex; gap:10px; align-items:flex-end; padding:10px 10px 10px 16px; background:var(--surface); border:1px solid var(--border); border-radius:18px; }
			.bot-composer:focus-within{ border-color:var(--text-faint); }
			.bot-composer textarea{ flex:1; background:transparent; border:none; resize:none; color:var(--text); font-family:var(--dx-font); font-size:14.5px; line-height:1.55; padding:8px 0; max-height:180px; }
			.bot-composer textarea:focus{ outline:none; }
			.bot-composer textarea::placeholder{ color:var(--text-faint); }
			.bot-composer button{ border-radius:12px; padding:10px 18px; flex-shrink:0; }
			.bot-composer.is-locked{ opacity:.55; }
			.bot-composer.is-locked textarea{ cursor:not-allowed; }

			/* Attached-file chip: an uploaded .sql waiting to be migrated. It
			   sits above the composer so it reads as part of the next message,
			   not as something already sent. */
			.bot-attach{ margin-top:12px; display:inline-flex; align-items:center; gap:10px; max-width:100%; padding:8px 10px 8px 14px; background:var(--surface); border:1px solid var(--border); border-radius:12px; font-size:12.5px; color:var(--text); }
			.bot-attach-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
			.bot-attach-name em{ font-style:normal; color:var(--text-faint); }
			.bot-attach-x{ display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px; padding:0; flex-shrink:0; font-size:12px; line-height:1; background:transparent; color:var(--text-muted); border:1px solid var(--border); border-radius:7px; cursor:pointer; }
			.bot-attach-x:hover{ color:#fff; border-color:var(--text-muted); }

			/* Migration card: the visual summary of an inspect or apply, styled
			   like the wizard's report so the two read as the same feature. It
			   sits in the thread on the bot's side, wider than a bubble because
			   it is a panel, not a sentence. */
			.bot-card{ margin:14px 0; max-width:min(72%, 640px); padding:16px 18px; background:var(--surface); border:1px solid var(--border); border-radius:16px; }
			.bot-card.phase-apply{ border-color:color-mix(in srgb, var(--green) 40%, var(--border)); }
			.bot-card-head{ display:flex; align-items:center; gap:10px; }
			.bot-card-title{ font-weight:700; font-size:13.5px; color:var(--text); }
			.bot-card-file{ font-size:11px; color:var(--text-muted); background:var(--surface-alt); padding:2px 7px; border-radius:6px; }
			.bot-card-conf{ margin-left:auto; font-size:15px; font-weight:800; color:var(--text); }
			.bot-card-bar{ margin-top:10px; height:6px; border-radius:4px; background:var(--surface-alt); overflow:hidden; }
			.bot-card-bar > span{ display:block; height:100%; background:var(--green); border-radius:4px; }
			.bot-card-stats{ margin-top:12px; display:flex; flex-wrap:wrap; gap:8px; }
			.bot-card-stat{ font-size:11.5px; color:var(--text-muted); background:var(--surface-alt); padding:4px 10px; border-radius:8px; }
			.bot-card-stat strong{ color:var(--text); font-weight:800; margin-right:2px; }
			.bot-card-stat.tone-ok strong{ color:var(--green); }
			.bot-card-stat.tone-warn strong{ color:#d9a441; }
			.bot-card-stat.tone-bad strong{ color:var(--red-light); }
			.bot-card-notes{ margin:12px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:7px; }
			.bot-card-notes li{ display:flex; align-items:baseline; gap:8px; font-size:12px; color:var(--text-muted); line-height:1.45; }
			.bot-card-notes code{ font-size:11px; color:var(--text); background:var(--surface-alt); padding:1px 6px; border-radius:5px; }
			.bot-card-chip{ flex-shrink:0; font-size:9px; font-weight:700; letter-spacing:.04em; padding:2px 6px; border-radius:5px; text-transform:uppercase; }
			.bot-card-chip.sev-auto{ color:var(--green); background:color-mix(in srgb, var(--green) 16%, transparent); }
			.bot-card-chip.sev-review{ color:#d9a441; background:rgba(217,164,65,.16); }
			.bot-card-chip.sev-manual{ color:var(--red-light); background:var(--red-soft); }
			.bot-card-chip.sev-applied{ color:var(--green); background:color-mix(in srgb, var(--green) 16%, transparent); }
			.bot-card-chip.sev-failed{ color:var(--red-light); background:var(--red-soft); }
			.bot-card-more{ margin-top:9px; font-size:11.5px; color:var(--text-faint); }
			.bot-card-foot{ margin-top:11px; padding-top:10px; border-top:1px solid var(--border); font-size:12px; color:var(--text-muted); }

			/* MCP connect panel: endpoint, token minting, issued tokens. */
			.bot-foot{ margin-top:14px; display:flex; align-items:center; justify-content:center; gap:18px; }
			.bot-mcp{ margin-top:14px; padding:18px; background:var(--surface); border:1px solid var(--border); border-radius:16px; }
			.bot-mcp-lead{ margin:0 0 14px; font-size:12.5px; color:var(--text-muted); line-height:1.55; }
			.bot-mcp-field{ display:flex; flex-direction:column; gap:5px; font-size:10.5px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-faint); }
			.bot-mcp-field code{ font-size:12.5px; text-transform:none; letter-spacing:0; color:var(--text); background:var(--surface-alt); padding:8px 11px; border-radius:8px; word-break:break-all; }
			.bot-mcp-new{ margin-top:14px; padding:12px 14px; background:var(--red-soft); border:1px solid color-mix(in srgb, var(--red) 30%, transparent); border-radius:10px; display:flex; flex-wrap:wrap; align-items:center; gap:10px; font-size:12px; color:var(--text); }
			.bot-mcp-token{ flex:1 1 240px; font-size:12px; color:var(--text); background:var(--surface); padding:7px 10px; border-radius:7px; word-break:break-all; }
			.bot-mcp-form{ margin-top:14px; display:flex; gap:10px; }
			.bot-mcp-form input{ flex:1; background:var(--surface-alt); border:1px solid var(--border); border-radius:9px; color:var(--text); padding:9px 12px; font-size:13px; }
			.bot-mcp-list{ margin:16px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:2px; }
			.bot-mcp-list li{ display:flex; align-items:center; gap:12px; padding:9px 4px; border-top:1px solid var(--border); font-size:12.5px; }
			.bot-mcp-list li.is-revoked{ opacity:.5; }
			.bot-mcp-name{ color:var(--text); }
			.bot-mcp-name em{ color:var(--text-faint); font-style:normal; }
			.bot-mcp-meta{ margin-left:auto; font-size:11px; color:var(--text-faint); }
			.bot-mcp-badge{ font-size:9.5px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-muted); background:var(--surface-alt); padding:2px 7px; border-radius:5px; }

			/* Conversation switcher: the active thread is marked, and each title
			   is a link that opens it. */
			.bot-newchat{ display:inline-flex; align-items:center; text-decoration:none; }
			.bot-conv-open{ text-decoration:none; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; }
			.bot-conv-open:hover{ color:#fff; }
			.bot-mcp-list li.is-active{ background:var(--red-soft); border-radius:8px; padding-left:8px; padding-right:8px; }
			.bot-mcp-list li.is-active .bot-conv-open{ color:#fff; font-weight:600; }

			/* Banner above the composer. The info variant is deliberately not
			   red: an informational line styled as a failure reads as
			   something broken. */
			.bot-alert{ margin-top:14px; display:flex; gap:12px; align-items:flex-start; padding:15px 18px; border-radius:14px; background:var(--red-soft); border:1px solid color-mix(in srgb, var(--red) 34%, transparent); }
			.bot-alert .bot-alert-i{ color:var(--red-light); font-weight:700; flex-shrink:0; }
			.bot-alert p{ margin:0; font-size:14px; line-height:1.55; color:var(--text); }
			.bot-alert a{ color:var(--red-light); border-bottom:1px solid currentColor; }
			.bot-alert.is-info{ background:var(--surface-alt); border-color:var(--border); }
			.bot-alert.is-info .bot-alert-i{ color:var(--text-faint); font-style:italic; }
			.bot-alert.is-info p{ color:var(--text-muted); }

			/* Thread: scrolls inside itself so the composer stays put. */
			.bot-thread{ max-height:56vh; overflow-y:auto; }

			/* Tool steps of the turn in flight. They are progress, not
			   content: muted, small, and replaced by the answer on reload. */
			.bot-steps{ align-self:flex-start; display:flex; flex-wrap:wrap; gap:6px; }
			.bot-step{ font-size:11.5px; color:var(--text-faint); background:var(--bg); border:1px solid var(--border); border-radius:99px; padding:4px 11px; }
			.bot-step::before{ content:'· '; color:var(--red); }

			/* Blinking caret while the answer streams in. */
			.bot-caret{ display:inline-block; width:7px; height:15px; margin-left:2px; vertical-align:text-bottom; background:var(--red); animation:bot-blink 1.05s steps(2,start) infinite; }
			@keyframes bot-blink{ to{ visibility:hidden; } }
			@media (prefers-reduced-motion:reduce){ .bot-caret{ animation:none; } }

			/* Link-looking button: a secondary action inside the access bar
			   that must not compete with the effort control next to it. */
			.bot-linkish{ background:transparent; border:none; padding:0; font-size:11.5px; font-weight:600; text-transform:none; letter-spacing:0; color:var(--red-light); border-bottom:1px solid currentColor; border-radius:0; }
			.bot-linkish:hover{ color:#fff; filter:none; }

			/* Loading a personal key from the console, not only from the gate. */
			.bot-keyform{ margin-top:12px; padding:18px 20px; background:var(--surface); border:1px solid var(--border); border-radius:16px; }
			.bot-keyform label{ display:block; font-size:12.5px; color:var(--text-muted); }
			.bot-keyform input{ width:100%; margin-top:7px; }
			.bot-keyform p{ margin:11px 0 0; font-size:12.5px; line-height:1.55; color:var(--text-faint); }
			.bot-keyform-actions{ display:flex; gap:8px; justify-content:flex-end; margin-top:16px; }

			.bot-reset{ margin-top:12px; display:flex; justify-content:center; }
			.bot-reset button{ font-size:10.5px; padding:6px 14px; }
			[x-cloak]{ display:none !important; }
			/* App Builder · región de componente con código (sandbox) */
			.ab-sandbox{ width:100%; }
			.ab-sandbox-frame{ display:block; width:100%; height:120px; border:0;
			                   background:transparent; color-scheme:dark; }
			.ab-comp-sandboxed{ color:#c9a227; border-color:rgba(201,162,39,.4); background:rgba(201,162,39,.10); }
			.ab-comp-sandboxnote{ margin:0 0 10px; padding:10px 13px; font-size:12px; line-height:1.55;
			                      color:var(--text-muted); background:rgba(201,162,39,.08);
			                      border-left:2px solid #c9a227; border-radius:0 8px 8px 0; }
			.ab-comp-sandboxnote strong{ color:var(--text); }
