{"id":5472,"date":"2026-05-11T02:57:40","date_gmt":"2026-05-11T02:57:40","guid":{"rendered":"https:\/\/ruvic.ai\/?page_id=5472"},"modified":"2026-07-12T01:41:45","modified_gmt":"2026-07-12T01:41:45","slug":"demos","status":"publish","type":"page","link":"https:\/\/ruvic.ai\/en\/demos\/","title":{"rendered":"Demos"},"content":{"rendered":"\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800\" rel=\"stylesheet\">\n\n\n\n<div id=\"rv-demovoz\" class=\"rv-demovoz\">\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Syne:wght@500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:wght@400;500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=JetBrains+Mono:wght@400;500');\n\n\/* ============ RUVIC \u00b7 Secci\u00f3n Demo Voz IA (bloque WP autocontenido) ============\n   El JS de conexi\u00f3n vive en Snippets: este bloque solo aporta HTML + estilos.\n   IDs que el snippet espera (NO renombrar): rwToggle, rwOrb, rwMeter,\n   rwStatusDot, rwStatusText, rwBtnMute, rwIconMicOn, rwIconMicOff, rwLocalWarn. *\/\n\n.rv-demovoz{\n  --navy:#0E1632;\n  --navy-card:#131B3D;\n  --coral:#FF363A;\n  --coral-act:#E4262B;\n  --amber:#FDAA4C;\n  --cream:#FDF2E1;\n  --ink-soft:#4A5170;\n  --ok:#189A4A;\n  --display:'Syne',sans-serif;\n  --body:'DM Sans',sans-serif;\n  --mono:'JetBrains Mono',monospace;\n  --maxw:1200px;\n  background:#0A0E1F;\n  color:#fff;\n  font-family:var(--body);\n  font-size:1rem;line-height:1.7;\n  -webkit-font-smoothing:antialiased;\n  position:relative;overflow:hidden;\n}\n.rv-demovoz,.rv-demovoz *{box-sizing:border-box;margin:0;padding:0}\n.rv-demovoz::before{\n  content:\"\";position:absolute;inset:0;pointer-events:none;\n  background:\n    radial-gradient(46% 42% at 82% 8%, rgba(255,54,58,.07), transparent 70%),\n    radial-gradient(38% 44% at 10% 90%, rgba(253,170,76,.05), transparent 72%);\n}\n.rv-demovoz .wrap{max-width:var(--maxw);margin:0 auto;padding:96px 24px !important;position:relative;z-index:1}\n.rv-demovoz .grid{display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}\n@media(max-width:900px){.rv-demovoz .grid{grid-template-columns:1fr;gap:44px}}\n\n\/* ---------- Copy izquierda ---------- *\/\n.rv-demovoz .kicker{\n  font-family:var(--mono);font-size:.72rem;font-weight:500;\n  letter-spacing:.14em;text-transform:uppercase;color:var(--amber);\n  display:block;margin-bottom:16px;\n}\n.rv-demovoz h2{\n  font-family:var(--display);font-weight:600;color:#fff;\n  font-size:clamp(1.9rem,3.8vw,3rem);line-height:1.08;letter-spacing:-.025em;\n  margin-bottom:20px;\n}\n.rv-demovoz h2 .accent{color:var(--coral)}\n.rv-demovoz .lead{font-size:1.12rem;line-height:1.6;color:rgba(255,255,255,.75);max-width:54ch;margin-bottom:28px}\n.rv-demovoz .points{list-style:none;display:flex;flex-direction:column;gap:14px}\n.rv-demovoz .points li{display:flex;gap:12px;align-items:flex-start;color:rgba(255,255,255,.82);font-size:.98rem;line-height:1.55}\n.rv-demovoz .points li i{\n  flex-shrink:0;width:22px;height:22px;border-radius:50%;\n  background:rgba(253,170,76,.16);color:var(--amber);\n  display:inline-flex;align-items:center;justify-content:center;\n  font-style:normal;font-size:12px;font-weight:700;margin-top:2px;\n}\n\n\/* ---------- Widget ---------- *\/\n.rv-demovoz .rvp-demo-wrap{display:flex;justify-content:center}\n.rv-demovoz .rvp-widget{\n  width:100%;max-width:400px;\n  background:var(--navy-card);\n  border:1px solid rgba(255,255,255,.10);\n  border-radius:20px;\n  padding:28px 26px 26px;\n  box-shadow:0 40px 90px -40px rgba(0,0,0,.75);\n  position:relative;overflow:hidden;\n  text-align:center;\n}\n.rv-demovoz .rvp-widget::before{\n  content:\"\";position:absolute;top:-80px;right:-80px;width:240px;height:240px;\n  background:radial-gradient(circle,rgba(255,54,58,.14),transparent 70%);\n  pointer-events:none;\n}\n.rv-demovoz .rw-logo-row{display:flex;align-items:center;justify-content:center;gap:9px;margin-bottom:22px;position:relative}\n.rv-demovoz .rw-logo-dot{width:9px;height:9px;border-radius:50%;background:var(--coral);box-shadow:0 0 0 0 rgba(255,54,58,.5);animation:rvdz-pulse 2s infinite}\n@keyframes rvdz-pulse{0%,100%{box-shadow:0 0 0 0 rgba(255,54,58,.45)}60%{box-shadow:0 0 0 8px rgba(255,54,58,0)}}\n.rv-demovoz .rw-logo-text{font-family:var(--mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;color:rgba(255,255,255,.55)}\n.rv-demovoz .rw-agent-name{font-family:var(--display);font-weight:600;font-size:1.25rem;color:#fff;position:relative}\n.rv-demovoz .rw-agent-sub{font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:rgba(255,255,255,.5);margin-top:4px;position:relative}\n\n\/* orb *\/\n.rv-demovoz .rw-orb-wrap{display:flex;justify-content:center;margin:26px 0 20px;position:relative}\n.rv-demovoz .rw-orb-stack{position:relative;display:inline-flex}\n.rv-demovoz .rw-orb{\n  width:104px;height:104px;border-radius:50%;\n  background:radial-gradient(circle at 34% 30%, #FF5257, var(--coral-act) 62%, #B01418);\n  display:flex;align-items:center;justify-content:center;\n  box-shadow:0 18px 44px -14px rgba(228,38,43,.55), inset 0 2px 10px rgba(255,255,255,.18);\n  position:relative;\n}\n.rv-demovoz .rw-orb::after{\n  content:\"\";position:absolute;inset:-9px;border-radius:50%;\n  border:1.5px dashed rgba(255,255,255,.28);\n  animation:rvdz-spin 14s linear infinite;\n}\n@keyframes rvdz-spin{to{transform:rotate(360deg)}}\n.rv-demovoz .rw-orb svg{width:38px;height:38px}\n.rv-demovoz .rw-btn-mute{\n  position:absolute;right:-6px;bottom:-2px;\n  width:36px;height:36px;border-radius:50%;\n  background:#0B1229;border:1px solid rgba(255,255,255,.18);\n  color:rgba(255,255,255,.75);cursor:pointer;\n  display:inline-flex;align-items:center;justify-content:center;\n  transition:background .2s ease,color .2s ease,transform .18s ease;\n}\n.rv-demovoz .rw-btn-mute svg{width:17px;height:17px}\n.rv-demovoz .rw-btn-mute:hover{background:#1A2450;color:#fff;transform:translateY(-1px)}\n.rv-demovoz .rw-btn-mute:disabled{opacity:.4;cursor:not-allowed;transform:none}\n.rv-demovoz .rw-btn-mute[aria-pressed=\"true\"]{background:rgba(255,54,58,.18);border-color:rgba(255,54,58,.5);color:#FF7A7D}\n\n\/* medidor de micr\u00f3fono *\/\n.rv-demovoz .rw-meter-row{display:flex;align-items:center;gap:12px;margin-bottom:14px;position:relative}\n.rv-demovoz .rw-meter-label{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.45);flex-shrink:0}\n.rv-demovoz .rw-meter-wrap{flex:1;height:6px;border-radius:99px;background:rgba(255,255,255,.08);overflow:hidden}\n.rv-demovoz .rw-meter-bar{\n  height:100%;width:0%;border-radius:99px;\n  background:linear-gradient(90deg,var(--amber),var(--coral));\n  transition:width .09s linear;\n}\n\n\/* estado *\/\n.rv-demovoz .rw-status-row{display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:18px;position:relative}\n.rv-demovoz .rw-status-dot{width:8px;height:8px;border-radius:50%;background:#9AA0B4;transition:background .25s ease}\n.rv-demovoz .rw-status-text{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:rgba(255,255,255,.6)}\n\/* estados que aplica el snippet JS (connecting\/active\/error\/ended) *\/\n.rv-demovoz .rw-status-dot.connecting{background:var(--amber);animation:rvdz-pulse 1.4s infinite}\n.rv-demovoz .rw-status-dot.active{background:var(--ok)}\n.rv-demovoz .rw-status-dot.error{background:var(--coral)}\n.rv-demovoz .rw-status-dot.ended{background:#9AA0B4}\n.rv-demovoz .rw-status-text.connecting{color:var(--amber)}\n.rv-demovoz .rw-status-text.active{color:#4ED07E}\n.rv-demovoz .rw-status-text.error{color:#FF7A7D}\n.rv-demovoz .rw-orb.active{animation:rvdz-orb-breathe 1.6s ease-in-out infinite}\n@keyframes rvdz-orb-breathe{\n  0%,100%{transform:scale(1);box-shadow:0 18px 44px -14px rgba(228,38,43,.55), inset 0 2px 10px rgba(255,255,255,.18)}\n  50%{transform:scale(1.05);box-shadow:0 22px 54px -14px rgba(228,38,43,.75), inset 0 2px 10px rgba(255,255,255,.18)}\n}\n.rv-demovoz .rw-btn-main.stop{background:#1A2450;border-color:rgba(255,255,255,.25)}\n.rv-demovoz .rw-btn-main.stop:hover{background:#232F63;box-shadow:0 14px 34px -12px rgba(0,0,0,.5)}\n\n\/* bot\u00f3n principal *\/\n.rv-demovoz .rw-btn-main{\n  width:100%;\n  font-family:var(--body);font-weight:600;font-size:15px;color:#fff;\n  background:var(--coral-act);border:1px solid transparent;border-radius:999px;\n  padding:15px 24px;cursor:pointer;position:relative;\n  transition:transform .18s ease,box-shadow .18s ease,background .18s ease;\n}\n.rv-demovoz .rw-btn-main:hover{transform:translateY(-2px);box-shadow:0 14px 34px -12px rgba(228,38,43,.55)}\n.rv-demovoz .rw-btn-main:active{transform:translateY(0)}\n\n\/* aviso file:\/\/ (el snippet lo muestra solo cuando aplica) *\/\n.rv-demovoz .rw-local-warn{\n  display:none;\n  margin-top:14px;padding:10px 14px;border-radius:10px;\n  background:rgba(253,170,76,.12);border:1px solid rgba(253,170,76,.3);\n  font-size:12.5px;line-height:1.5;color:var(--amber);text-align:left;position:relative;\n}\n.rv-demovoz .rw-local-warn code{font-family:var(--mono);font-size:11.5px}\n\n.rv-demovoz .rw-hint{\n  margin-top:18px;font-size:13px;line-height:1.6;\n  color:rgba(255,255,255,.55);position:relative;\n}\n.rv-demovoz .rw-hint strong{color:rgba(255,255,255,.85);font-weight:600}\n\n@media (prefers-reduced-motion:reduce){\n  .rv-demovoz .rw-logo-dot{animation:none}\n  .rv-demovoz .rw-orb::after{animation:none}\n}\n@media(max-width:560px){\n  .rv-demovoz .wrap{padding:72px 20px !important}\n  .rv-demovoz .rvp-widget{padding:24px 18px 22px}\n}\n<\/style>\n\n<!-- ============ SECCI\u00d3N DEMO \u00b7 VOZ IA ============ -->\n<section class=\"wrap\" aria-label=\"Demo en vivo del agente de voz de Ruvic\">\n  <div class=\"grid\">\n\n    <div>\n      <span class=\"kicker\">Demo en vivo \u00b7 Voz IA<\/span>\n      <h2>No te lo contamos: <span class=\"accent\">h\u00e1blalo con Ruvic<\/span>.<\/h2>\n      <p class=\"lead\">Presiona el bot\u00f3n y conversa en tiempo real con un agente de voz IA. Sin formularios, sin esperas: una llamada directa desde tu navegador.<\/p>\n      <ul class=\"points\">\n        <li><i>\u2713<\/i>Conversaci\u00f3n natural con latencia de milisegundos<\/li>\n        <li><i>\u2713<\/i>Entiende la intenci\u00f3n sin men\u00fas ni extensiones<\/li>\n        <li><i>\u2713<\/i>Disponible 24\/7, igual que en tu operaci\u00f3n real<\/li>\n      <\/ul>\n    <\/div>\n\n    <div class=\"rvp-demo-wrap\">\n      <div class=\"rvp-widget\">\n        <div class=\"rw-logo-row\">\n          <div class=\"rw-logo-dot\"><\/div>\n          <span class=\"rw-logo-text\">RUVIC VOICE \u00b7 AI CALL AGENT<\/span>\n        <\/div>\n        <div class=\"rw-agent-name\">Voice Agent<\/div>\n        <div class=\"rw-agent-sub\">Sesi\u00f3n de audio en tiempo real<\/div>\n        <div class=\"rw-orb-wrap\">\n          <div class=\"rw-orb-stack\">\n            <div class=\"rw-orb\" id=\"rwOrb\">\n              <svg viewBox=\"0 0 24 24\" fill=\"none\">\n                <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" stroke=\"rgba(245,245,248,0.75)\" stroke-width=\"1.8\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"rgba(245,245,248,0.75)\" stroke-width=\"1.8\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M12 19v4M8 23h8\" stroke=\"rgba(245,245,248,0.75)\" stroke-width=\"1.8\" stroke-linecap=\"round\"><\/path>\n              <\/svg>\n            <\/div>\n            <button type=\"button\" class=\"rw-btn-mute\" id=\"rwBtnMute\" disabled aria-pressed=\"false\" aria-label=\"Silenciar micr\u00f3fono\" title=\"Silenciar micr\u00f3fono\">\n              <svg id=\"rwIconMicOn\" viewBox=\"0 0 24 24\" fill=\"none\">\n                <path d=\"M12 14a3 3 0 0 0 3-3V5a3 3 0 1 0-6 0v6a3 3 0 0 0 3 3z\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M19 10v1a7 7 0 0 1-14 0v-1\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M12 19v3M9 22h6\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n              <\/svg>\n              <svg id=\"rwIconMicOff\" viewBox=\"0 0 24 24\" fill=\"none\" style=\"display:none\">\n                <path d=\"M2 2l20 20\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V5a3 3 0 0 0-5-2.24\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M17 17c-1.2 1-2.8 1.6-4.5 1.6-1.2 0-2.3-.3-3.3-.8\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n                <path d=\"M12 19v3M9 22h6M19 10v1c0 .7-.1 1.4-.3 2\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"><\/path>\n              <\/svg>\n            <\/button>\n          <\/div>\n        <\/div>\n        <div class=\"rw-meter-row\">\n          <span class=\"rw-meter-label\">Micr\u00f3fono<\/span>\n          <div class=\"rw-meter-wrap\"><div class=\"rw-meter-bar\" id=\"rwMeter\"><\/div><\/div>\n        <\/div>\n        <div class=\"rw-status-row\">\n          <div class=\"rw-status-dot\" id=\"rwStatusDot\"><\/div>\n          <span class=\"rw-status-text\" id=\"rwStatusText\" role=\"status\" aria-live=\"polite\">Desconectado<\/span>\n        <\/div>\n        <button type=\"button\" class=\"rw-btn-main\" id=\"rwToggle\">\ud83d\udcde Llamar a RUVIC<\/button>\n        <div class=\"rw-local-warn\" id=\"rwLocalWarn\">\n          \u26a0 Est\u00e1s abriendo este archivo desde <code>file:\/\/<\/code>. Los navegadores bloquean el acceso al micr\u00f3fono en ese origen.\n        <\/div>\n        <p class=\"rw-hint\">\n          \u00bfListo para transformar tu operaci\u00f3n? RUVIC gestiona llamadas, resuelve consultas y escala sin l\u00edmites \u2014 las 24 horas, los 7 d\u00edas de la semana.\n          <br><br>\n          <strong>Habla con nosotros y descubre lo que un agente de IA puede hacer por tu negocio.<\/strong>\n        <\/p>\n      <\/div>\n    <\/div>\n\n  <\/div>\n<\/section>\n<\/div>\n\n\n\n\n<style id=\"ruvic-css\">\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Syne:wght@500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:wght@400;500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=JetBrains+Mono:wght@400;500');\n\n\/* ============================================================\n   RUVIC AI \u2014 DEMO INTERACTIVA  \u00b7  bloque WordPress autocontenido\n   Todo el CSS est\u00e1 namespaced bajo #ruvic-demo para no chocar\n   con el tema de WordPress. Toggle claro\/oscuro incluido.\n   ============================================================ *\/\n\n#ruvic-demo, #ruvic-demo *{box-sizing:border-box;margin:0;padding:0;line-height:1.4}\n#ruvic-demo{\n  --font:'Plus Jakarta Sans',system-ui,-apple-system,sans-serif;\n  font-family:var(--font);\n  width:100%;max-width:1400px;margin:0 auto;\n  padding:30px 30px 34px;\n  border-radius:30px;\n  position:relative;\n  -webkit-font-smoothing:antialiased;\n  text-align:left;\n  isolation:isolate;\n}\n#ruvic-demo *{font-family:var(--font)}\n\n\/* Fondo navy profundo que rodea el widget \u2014 se extiende a todo el ancho.\n   La t\u00e9cnica de m\u00e1rgenes negativos lo lleva de borde a borde de la pantalla;\n   si la secci\u00f3n tiene overflow oculto, simplemente queda al ancho del contenido. *\/\n#ruvic-bg{background:#0E1632;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);\n  padding:48px clamp(14px,4vw,40px)}\n\n\/* ---------- TEMA OSCURO (por defecto, colores actuales) ---------- *\/\n#ruvic-demo[data-theme=\"dark\"]{\n  --surface:#111b3d; --surface2:#0d1530; --sb:#0f1834; --sb2:rgba(0,0,0,.28);\n  --card-hi:#1b2658; --card:#141e48; --ghost:#172148;\n  --border:rgba(250,240,228,.12); --border2:rgba(250,240,228,.2);\n  --text:#faf0e4; --text2:rgba(250,240,228,.62); --text3:rgba(250,240,228,.34);\n  --red:#ff363a; --orange:#fdaa4c; --purple:#8b80ff;\n  --grid:rgba(250,240,228,.05); --glow:rgba(83,74,183,.30);\n  --shadow:0 36px 70px -28px rgba(0,0,0,.7); --nshadow:0 3px 10px -2px rgba(0,0,0,.4);\n  --kpi-bg:rgba(253,170,76,.16); --kpi-tx:#fdaa4c;\n  background:\n    radial-gradient(130% 90% at 50% -10%, #18244f 0%, #0d1430 52%, #090e22 100%);\n  box-shadow:inset 0 1px 0 rgba(250,240,228,.05);\n}\n\/* ---------- TEMA CLARO (versi\u00f3n white) ---------- *\/\n#ruvic-demo[data-theme=\"light\"]{\n  --surface:#ffffff; --surface2:#f6f8fd; --sb:#ffffff; --sb2:#f6f8fd;\n  --card-hi:#ffffff; --card:#fbfcfe; --ghost:#f1f4fb;\n  --border:rgba(22,26,55,.1); --border2:rgba(22,26,55,.16);\n  --text:#161a33; --text2:rgba(22,26,51,.6); --text3:rgba(22,26,51,.4);\n  --red:#ff363a; --orange:#e8890a; --purple:#534AB7;\n  --grid:rgba(22,26,55,.05); --glow:rgba(83,74,183,.14);\n  --shadow:0 30px 60px -28px rgba(30,40,90,.32); --nshadow:0 6px 16px -8px rgba(30,40,90,.22);\n  --kpi-bg:rgba(232,137,10,.12); --kpi-tx:#c9760a;\n  background:\n    radial-gradient(120% 90% at 50% -10%, #ffffff 0%, #eef1fa 60%, #e6eaf6 100%);\n  box-shadow:inset 0 1px 0 rgba(255,255,255,.6);\n}\n\n\/* ---------------- HEADER ---------------- *\/\n#ruvic-demo .rb-header{position:relative;text-align:center;padding:6px 96px 26px}\n#ruvic-demo .rb-eyebrow{display:inline-flex;align-items:center;gap:9px;font-family:'JetBrains Mono',monospace;font-size:.72rem;font-weight:500;white-space:nowrap;\n  letter-spacing:.14em;color:var(--orange);text-transform:uppercase}\n#ruvic-demo .rb-eyebrow .pd{width:7px;height:7px;border-radius:50%;background:var(--orange);\n  box-shadow:0 0 0 0 rgba(253,170,76,.7);animation:rbPing 1.8s ease-out infinite}\n@keyframes rbPing{0%{box-shadow:0 0 0 0 rgba(253,170,76,.55)}\n  70%{box-shadow:0 0 0 8px transparent}100%{box-shadow:0 0 0 0 transparent}}\n#ruvic-demo .rb-title{margin:16px 0 0;font-family:'Syne',sans-serif;font-size:clamp(1.9rem,3.8vw,3rem);line-height:1.08;font-weight:600;letter-spacing:-.025em;color:var(--text);text-wrap:balance}\n#ruvic-demo .rb-title .ac{color:var(--red)}\n#ruvic-demo .rb-sub{margin:14px auto 0;max-width:600px;font-family:'DM Sans',sans-serif;font-size:1.05rem;line-height:1.6;color:var(--text2);text-wrap:pretty}\n\n\/* Theme toggle *\/\n#ruvic-demo .rb-theme{position:absolute;top:2px;right:0;display:inline-flex;align-items:center;gap:0;\n  background:var(--ghost);border:1px solid var(--border);border-radius:100px;padding:4px;cursor:pointer;\n  user-select:none}\n#ruvic-demo .rb-theme i{width:30px;height:28px;border-radius:100px;display:flex;align-items:center;justify-content:center;\n  font-style:normal;font-size:14px;color:var(--text3);transition:all .25s;position:relative;z-index:1}\n#ruvic-demo .rb-theme .knob{position:absolute;top:4px;left:4px;width:30px;height:28px;border-radius:100px;\n  background:linear-gradient(180deg,var(--red),#e02d31);box-shadow:0 4px 10px -3px var(--red);transition:transform .28s cubic-bezier(.5,1.4,.5,1)}\n#ruvic-demo[data-theme=\"light\"] .rb-theme .knob{transform:translateX(30px)}\n#ruvic-demo[data-theme=\"dark\"] .rb-theme i.moon{color:#fff}\n#ruvic-demo[data-theme=\"light\"] .rb-theme i.sun{color:#fff}\n\n\/* ---------------- WIDGET CARD ---------------- *\/\n#ruvic-demo .rb-widget{position:relative;border-radius:24px;overflow:hidden;height:750px;\n  background:var(--surface);border:1px solid var(--border2);box-shadow:var(--shadow);\n  display:grid;grid-template-columns:1fr 310px}\n#ruvic-demo[data-theme=\"dark\"] .rb-widget::after{content:\"\";position:absolute;inset:0;border-radius:24px;pointer-events:none;\n  box-shadow:inset 0 1px 0 rgba(250,240,228,.08)}\n#ruvic-demo[data-theme=\"light\"] .rb-widget::after{content:\"\";position:absolute;inset:0;border-radius:24px;pointer-events:none;\n  box-shadow:inset 0 1px 0 rgba(22,26,51,.08)}\n\n\/* ---- diagrama (canvas) ---- *\/\n#ruvic-demo .rb-canvas-area{position:relative;overflow:hidden;height:100%;\n  background:\n    radial-gradient(circle at 41% 42%, var(--glow) 0%, transparent 46%),\n    radial-gradient(var(--grid) 1.1px, transparent 1.1px);\n  background-size:auto, 26px 26px;background-color:var(--surface2)}\n#ruvic-demo .rb-zp{position:absolute;top:0;left:0;transform-origin:0 0}\n#ruvic-demo #rb-fc{position:absolute;top:0;left:0;z-index:1}\n#ruvic-demo .rb-nl{position:absolute;top:0;left:0;z-index:2;pointer-events:none}\n#ruvic-demo .rb-nl>*{pointer-events:auto}\n#ruvic-demo .rb-hint{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);z-index:4;\n  font-size:10.5px;font-weight:600;color:var(--text3);background:var(--sb2);\n  border:1px solid var(--border);padding:5px 12px;border-radius:100px;display:none;pointer-events:none}\n\n\/* ---- sidebar ---- *\/\n#ruvic-demo .rb-sb{background:var(--sb);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;min-height:0}\n#ruvic-demo .rb-sb-head{padding:18px 18px 14px;border-bottom:1px solid var(--border);display:flex;gap:11px;align-items:flex-start}\n#ruvic-demo .rb-mark{width:34px;height:34px;border-radius:10px;flex-shrink:0;display:flex;align-items:center;justify-content:center;\n  font-weight:800;font-size:16px;color:#fff;background:linear-gradient(150deg,var(--red),#b41f5e);\n  box-shadow:0 6px 16px -6px var(--red)}\n#ruvic-demo .rb-sb-head h3{font-size:15px;font-weight:800;color:var(--text);letter-spacing:-.3px;line-height:17px}\n#ruvic-demo .rb-sb-head h3 b{color:var(--red);font-weight:800}\n#ruvic-demo .rb-sb-head p{font-size:10.5px;color:var(--text3);margin-top:4px;line-height:15px}\n#ruvic-demo .rb-filter{padding:11px 18px;border-bottom:1px solid var(--border);display:flex;gap:6px;flex-wrap:wrap}\n#ruvic-demo .rb-filter::-webkit-scrollbar{display:none}\n#ruvic-demo .fb{padding:6px 11px;line-height:14px;border:1px solid var(--border2);border-radius:9px;font-size:10.5px;font-weight:600;cursor:pointer;flex-shrink:0;white-space:nowrap;\n  background:var(--ghost);color:var(--text2);transition:color .15s,border-color .15s,box-shadow .15s;line-height:1}\n#ruvic-demo .fb:hover{border-color:var(--orange);color:var(--orange);box-shadow:none !important}\n#ruvic-demo .fb.act{background:#ff363a !important;color:#fff !important;border-color:#ff363a !important;box-shadow:0 4px 12px -4px #ff363a !important}\n#ruvic-demo .rb-cases{flex:1;overflow-y:auto;padding:12px 14px;min-height:0}\n#ruvic-demo .rb-cases::-webkit-scrollbar, #ruvic-demo .rb-trk::-webkit-scrollbar{width:5px}\n#ruvic-demo .rb-cases::-webkit-scrollbar-thumb, #ruvic-demo .rb-trk::-webkit-scrollbar-thumb{background:var(--border2);border-radius:5px}\n#ruvic-demo .cb{width:100%;text-align:left;padding:12px 14px;border:1.5px solid var(--border);border-radius:13px;\n  background:var(--card);cursor:pointer;margin-bottom:8px;transition:transform .18s,box-shadow .18s,border-color .18s;display:block;position:relative;overflow:hidden}\n#ruvic-demo .cb::before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cbc,var(--red));opacity:0;transition:opacity .2s}\n#ruvic-demo .cb:hover{border-color:var(--orange);transform:translateY(-2px);box-shadow:0 10px 24px -12px rgba(0,0,0,.4) !important}\n#ruvic-demo[data-theme=\"dark\"] .cb.act{border-color:#ff363a !important;background:#1e1d48 !important;box-shadow:0 8px 24px -10px rgba(255,54,58,.6) !important}\n#ruvic-demo[data-theme=\"light\"] .cb.act{border-color:#ff363a !important;background:#fce9e9 !important;box-shadow:0 8px 24px -10px rgba(255,54,58,.6) !important}\n#ruvic-demo .cb.act::before{opacity:1}\n#ruvic-demo .cb-ch{font-size:9px;line-height:12px;font-weight:800;text-transform:uppercase;letter-spacing:1px;color:var(--text3);display:flex;align-items:center;gap:6px}\n#ruvic-demo .cb-ch .d{width:7px;height:7px;border-radius:50%;flex-shrink:0}\n#ruvic-demo .cb-t{font-size:13px;font-weight:700;color:var(--text);line-height:17px;margin-top:5px}\n#ruvic-demo .cb-desc{font-size:11px;color:var(--text2);margin-top:4px;line-height:15px}\n#ruvic-demo .cb-kpi{display:inline-flex;line-height:13px;align-items:center;gap:4px;margin-top:8px;font-size:9.5px;font-weight:800;padding:4px 9px;border-radius:7px;background:var(--kpi-bg);color:var(--kpi-tx)}\n\n\/* tracker *\/\n#ruvic-demo .rb-trk{border-top:1px solid var(--border);padding:14px 18px;background:var(--sb2);max-height:248px;overflow-y:auto}\n#ruvic-demo .rb-trk h4{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:1px;color:var(--text3);margin-bottom:11px;display:flex;justify-content:space-between;align-items:center}\n#ruvic-demo .rb-trk h4 span{color:var(--orange);font-weight:800}\n#ruvic-demo .rb-empty{font-size:11px;color:var(--text3);line-height:17px}\n#ruvic-demo .stp{display:flex;gap:11px;margin-bottom:10px;opacity:.3;transition:opacity .35s,transform .35s}\n#ruvic-demo .stp:last-child{margin-bottom:2px}\n#ruvic-demo .stp.on{opacity:1;transform:translateX(3px)}\n#ruvic-demo .stp.dn{opacity:.5}\n#ruvic-demo .stp-n{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:9.5px;font-weight:800;color:#fff;flex-shrink:0;box-shadow:0 3px 8px -2px rgba(0,0,0,.4)}\n#ruvic-demo .stp-n.pulse{animation:rbPulse .55s ease}\n@keyframes rbPulse{0%{transform:scale(1)}45%{transform:scale(1.32)}100%{transform:scale(1)}}\n#ruvic-demo .stp-i{flex:1;min-width:0}\n#ruvic-demo .stp-nm{font-size:11.5px;font-weight:700;color:var(--text);line-height:15px}\n#ruvic-demo .stp-dt{font-size:10px;color:var(--text2);margin-top:2px;line-height:14px}\n\n\/* controls *\/\n#ruvic-demo .rb-ctrls{padding:12px 18px 16px;border-top:1px solid var(--border);background:var(--sb2)}\n#ruvic-demo .rb-ctrls-row{display:flex;gap:8px;margin-bottom:11px}\n#ruvic-demo .btn{flex:1;padding:11px;border:none;border-radius:11px;font-size:11.5px;font-weight:800;cursor:pointer;transition:color .15s,border-color .15s,box-shadow .15s,filter .15s;display:flex;align-items:center;justify-content:center;gap:6px}\n#ruvic-demo .btn-play{background:linear-gradient(180deg,var(--red),#e02d31);color:#fff;box-shadow:0 8px 18px -8px var(--red);gap:0}\n#ruvic-demo .btn-play::before{content:\"\";display:inline-block;width:0;height:0;border-style:solid;border-width:5px 0 5px 9px;border-color:transparent transparent transparent #fff;margin-right:7px;flex-shrink:0}\n#ruvic-demo .btn-play:hover{filter:brightness(1.06);box-shadow:0 8px 18px -8px #ff363a !important}\n#ruvic-demo .btn-play:disabled{background:var(--ghost);color:var(--text3);cursor:not-allowed;box-shadow:none}\n#ruvic-demo .btn-play:disabled::before{border-left-color:var(--text3)}\n#ruvic-demo .btn-rst{background:var(--ghost);color:var(--text2);border:1px solid var(--border)}\n#ruvic-demo .btn-rst:hover{border-color:var(--border2);color:var(--text);box-shadow:none !important}\n#ruvic-demo .speed-row{display:flex;align-items:center;gap:10px}\n#ruvic-demo .speed-row label{font-size:10.5px;color:var(--text3);font-weight:700;white-space:nowrap}\n#ruvic-demo .speed-row input[type=range]{flex:1;height:6px;-webkit-appearance:none;appearance:none;border-radius:4px;outline:none;background:transparent;border:none !important;box-shadow:none !important;padding:0 !important}\n#ruvic-demo[data-theme=\"dark\"] .speed-row input[type=range]{background-color:#0b1125 !important;border-color:#0b1125 !important}\n#ruvic-demo .speed-row input[type=range]::-webkit-slider-runnable-track{height:6px;border-radius:4px;background:rgba(250,240,228,.25);border:none;box-shadow:none}\n#ruvic-demo[data-theme=\"light\"] .speed-row input[type=range]::-webkit-slider-runnable-track{background:rgba(22,26,51,.15)}\n#ruvic-demo .speed-row input[type=range]::-moz-range-track{height:6px;border-radius:4px;background:rgba(250,240,228,.25);border:none}\n#ruvic-demo[data-theme=\"light\"] .speed-row input[type=range]::-moz-range-track{background:rgba(22,26,51,.15)}\n#ruvic-demo .speed-row input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--orange);cursor:pointer;box-shadow:0 2px 8px -1px var(--orange);margin-top:-6px}\n#ruvic-demo .speed-row input[type=range]::-moz-range-thumb{width:18px;height:18px;border:none;border-radius:50%;background:var(--orange);cursor:pointer;box-shadow:0 2px 8px -1px var(--orange)}\n#ruvic-demo .speed-row .sv{font-size:11px;font-weight:800;color:var(--orange);min-width:24px;text-align:right}\n\n\/* ---------------- NODES ---------------- *\/\n#ruvic-demo .nd{position:absolute;display:flex;flex-direction:column;align-items:center;text-align:center;transition:opacity .5s,filter .5s;cursor:default}\n#ruvic-demo .nd.dim{opacity:.14;filter:grayscale(.85)}\n#ruvic-demo .nd.hl{z-index:5}\n#ruvic-demo .nd.clk{cursor:pointer}\n#ruvic-demo .nc{background:linear-gradient(180deg,var(--card-hi),var(--card));border:1.5px solid var(--border);border-radius:14px;padding:9px 11px;display:flex;flex-direction:column;align-items:center;gap:4px;min-width:104px;transition:border-color .35s,box-shadow .35s,transform .25s;box-shadow:var(--nshadow)}\n#ruvic-demo .nd.clk:hover .nc{transform:translateY(-2px);border-color:var(--orange);box-shadow:none !important}\n#ruvic-demo .nc.gp{box-shadow:0 0 28px var(--glow),var(--nshadow);border-color:#7c74e6}\n#ruvic-demo .nc.gt{box-shadow:0 0 28px rgba(16,185,129,.28),var(--nshadow);border-color:#10b981}\n#ruvic-demo .nc.go{box-shadow:0 0 28px rgba(249,115,22,.28),var(--nshadow);border-color:#f97316}\n#ruvic-demo .nc.gb{box-shadow:0 0 28px rgba(59,130,246,.28),var(--nshadow);border-color:#3b82f6}\n#ruvic-demo .nc.gr{box-shadow:0 0 28px rgba(239,68,68,.28),var(--nshadow);border-color:#ef4444}\n#ruvic-demo .nc-core{border:2.5px solid #7c74e6;box-shadow:0 0 40px var(--glow),0 18px 40px -16px rgba(83,74,183,.5);padding:17px 24px;min-width:208px;border-radius:20px;position:relative}\n\/* Iconos \u2014 ahora son <img> con SVG data-URI: aislados 100% del CSS de Kadence *\/\n#ruvic-demo .ic{width:36px !important;height:36px !important;border-radius:50%;display:block !important;flex-shrink:0;transition:transform .3s;box-shadow:0 5px 14px -5px rgba(0,0,0,.45);max-width:none !important;border:none !important;padding:0 !important;vertical-align:middle}\n#ruvic-demo .ic-lg{width:48px !important;height:48px !important;border-radius:14px}\n#ruvic-demo .ic-sm{width:30px !important;height:30px !important;border-radius:8px;box-shadow:0 3px 8px -3px rgba(0,0,0,.4);display:block !important;margin:0 auto !important;flex-shrink:0;max-width:none !important;border:none !important;padding:0 !important;vertical-align:middle}\n#ruvic-demo .ic.pulse{animation:rbNode .6s ease}\n@keyframes rbNode{0%{transform:scale(1)}40%{transform:scale(1.22)}100%{transform:scale(1)}}\n#ruvic-demo .ng{background:linear-gradient(180deg,var(--card-hi),var(--ghost));border:1px solid var(--border);border-radius:10px;padding:7px 10px;min-width:0;width:auto;transition:border-color .35s,box-shadow .35s;text-align:center;box-shadow:var(--nshadow)}\n#ruvic-demo .ng .nt{font-size:10px;white-space:nowrap;overflow:visible;line-height:13px}\n#ruvic-demo .nt{font-size:12px;font-weight:700;color:var(--text);line-height:15px}\n#ruvic-demo .nt-lg{font-size:16px;white-space:nowrap}\n#ruvic-demo .ns{font-size:10px;color:var(--text2);line-height:13px}\n#ruvic-demo .tg{font-size:8px;padding:3px 8px;border-radius:7px;font-weight:800;letter-spacing:.2px}\n#ruvic-demo .sl{position:absolute;font-size:10px;line-height:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.6px;color:var(--text3);pointer-events:none;white-space:nowrap}\n\n\/* ============ RESPONSIVE \/ M\u00d3VIL \u2014 layout 2 columnas, sin diagrama ============ *\/\n#ruvic-demo.is-narrow{padding:14px 10px 20px;border-radius:22px}\n#ruvic-demo.is-narrow .rb-header{padding:2px 4px 14px}\n#ruvic-demo.is-narrow .rb-title{font-size:22px;letter-spacing:-.5px}\n#ruvic-demo.is-narrow .rb-sub{font-size:13px;margin-top:8px}\n#ruvic-demo.is-narrow .rb-theme{top:0}\n\/* Diagrama arriba, panel 2 columnas abajo *\/\n#ruvic-demo.is-narrow .rb-canvas-area{\n  display:block;height:320px;width:100%;\n  border-bottom:1px solid var(--border);touch-action:none;\n}\n#ruvic-demo.is-narrow .rb-hint{display:block}\n#ruvic-demo.is-narrow .rb-hint{display:none}\n\/* Widget: bloque simple, altura autom\u00e1tica *\/\n#ruvic-demo.is-narrow .rb-widget{display:block;height:auto}\n\/* Sidebar: 2 columnas \u2014 casos | tracker+controles *\/\n#ruvic-demo.is-narrow .rb-sb{\n  display:grid;\n  grid-template-columns:58% 42%;\n  grid-template-rows:auto auto 1fr auto;\n  border-left:none;\n  height:420px;\n}\n#ruvic-demo.is-narrow .rb-sb-head{\n  grid-column:1;grid-row:1;\n  border-right:1px solid var(--border);border-bottom:1px solid var(--border);\n  padding:14px 12px;\n}\n#ruvic-demo.is-narrow .rb-sb-head h3{font-size:13px}\n#ruvic-demo.is-narrow .rb-sb-head p{font-size:10px}\n#ruvic-demo.is-narrow .rb-filter{\n  grid-column:1;grid-row:2;\n  border-right:1px solid var(--border);border-bottom:1px solid var(--border);\n  padding:8px 10px;gap:4px;\n  flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch;\n}\n#ruvic-demo.is-narrow .rb-cases{\n  grid-column:1;grid-row:3;\n  border-right:1px solid var(--border);\n  max-height:175px;flex:none;\n  overflow-y:auto;\n  padding:8px 10px;\n}\n#ruvic-demo.is-narrow .rb-cases .cb{padding:9px 10px;margin-bottom:6px}\n#ruvic-demo.is-narrow .rb-cases .cb-t{font-size:12px}\n#ruvic-demo.is-narrow .rb-cases .cb-desc{font-size:10px}\n#ruvic-demo.is-narrow .rb-trk{\n  grid-column:2;grid-row:1\/4;\n  max-height:none;border-top:none;\n  overflow-y:auto;\n  padding:12px 10px;\n}\n#ruvic-demo.is-narrow .rb-trk h4{font-size:9.5px}\n#ruvic-demo.is-narrow .stp-nm{font-size:10.5px}\n#ruvic-demo.is-narrow .stp-dt{font-size:9px}\n#ruvic-demo.is-narrow .rb-ctrls{\n  grid-column:1\/3;grid-row:4;\n  padding:8px 12px 12px;\n  border-top:1px solid var(--border);\n}\n#ruvic-demo.is-narrow .btn{font-size:10.5px;padding:9px}\n#ruvic-demo.is-narrow .speed-row label{font-size:9.5px}\n#ruvic-demo.is-narrow .sv{font-size:10px}\n\/* Ajuste tipograf\u00eda xnarrow *\/\n#ruvic-demo.is-xnarrow{padding:10px 8px 16px}\n#ruvic-demo.is-xnarrow .rb-title{font-size:19px}\n#ruvic-demo.is-xnarrow .rb-eyebrow{font-size:9px;letter-spacing:1.4px;padding:5px 9px}\n#ruvic-demo.is-xnarrow .rb-sb-head{padding:10px}\n#ruvic-demo.is-xnarrow .rb-theme{transform:scale(.9);transform-origin:top right}\n\n\n\n\/* ============ Animaciones v2 ============ *\/\n\/* Entrada en viewport: cabecera escalonada + widget con lift (gate .rv-anim la pone el JS) *\/\n#ruvic-demo.rv-anim .rb-eyebrow,\n#ruvic-demo.rv-anim .rb-title,\n#ruvic-demo.rv-anim .rb-sub{opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .7s cubic-bezier(.22,1,.36,1)}\n#ruvic-demo.rv-anim .rb-widget{opacity:0;transform:translateY(24px) scale(.985);transition:opacity .7s ease,transform .8s cubic-bezier(.22,1,.36,1)}\n#ruvic-demo.rv-anim .rb-title{transition-delay:.1s}\n#ruvic-demo.rv-anim .rb-sub{transition-delay:.18s}\n#ruvic-demo.rv-anim .rb-widget{transition-delay:.28s}\n#ruvic-demo.rv-anim.rv-in .rb-eyebrow,\n#ruvic-demo.rv-anim.rv-in .rb-title,\n#ruvic-demo.rv-anim.rv-in .rb-sub{opacity:1;transform:none}\n#ruvic-demo.rv-anim.rv-in .rb-widget{opacity:1;transform:none}\n\n\/* Nucleo del engine: respiracion del glow (opacity+transform, barato en GPU) *\/\n#ruvic-demo .nc-core::after{content:\"\";position:absolute;inset:-16px;border-radius:28px;z-index:-1;pointer-events:none;\n  background:radial-gradient(60% 60% at 50% 50%,var(--glow),transparent 72%);\n  animation:rbBreath 4.2s ease-in-out infinite}\n@keyframes rbBreath{0%,100%{opacity:.35;transform:scale(.96)}50%{opacity:.85;transform:scale(1.07)}}\n\n\/* Pasos del tracker: entrada con slide+fade *\/\n#ruvic-demo .stp.on{animation:rbStep .45s cubic-bezier(.22,1,.36,1)}\n@keyframes rbStep{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(3px)}}\n\n\/* Caso seleccionado: micro-rebote *\/\n#ruvic-demo .cb.act{animation:rbSel .5s cubic-bezier(.34,1.56,.64,1)}\n@keyframes rbSel{0%{transform:scale(.985)}60%{transform:scale(1.014)}100%{transform:scale(1)}}\n\n\/* Boton reproducir: barrido de luz al pasar el mouse *\/\n#ruvic-demo .btn-play{position:relative;overflow:hidden}\n#ruvic-demo .btn-play::after{content:\"\";position:absolute;top:0;bottom:0;left:-70%;width:45%;\n  background:linear-gradient(100deg,transparent,rgba(255,255,255,.38),transparent);\n  transform:skewX(-18deg);transition:left .55s ease;pointer-events:none}\n#ruvic-demo .btn-play:hover:not(:disabled)::after{left:130%}\n\n\/* Chips de filtro: feedback al presionar *\/\n#ruvic-demo .fb:active{transform:scale(.94)}\n#ruvic-demo .fb{transition:color .15s,border-color .15s,box-shadow .15s,transform .15s}\n\n\/* Kadence theme overrides *\/\n#ruvic-demo button:hover{box-shadow:none !important}\n#ruvic-demo button{line-height:14px}\n@media (prefers-reduced-motion:reduce){\n  #ruvic-demo *{animation-duration:.001ms!important;transition-duration:.08s!important}\n}\n\n\/* Nuclear reset \u2014 Kadence body\/global-palette color bleed fix\n   \"body #ruvic-demo\" tiene especificidad (0,1,1) y gana a \"body{color:...}\" de Kadence (0,0,1) *\/\nbody #ruvic-demo{color:#faf0e4}\nbody #ruvic-demo[data-theme=\"light\"]{color:#161a33}\nbody #ruvic-demo .nt{color:var(--text) !important}\nbody #ruvic-demo .ns{color:var(--text2) !important}\nbody #ruvic-demo .nt-lg{color:var(--text) !important}\nbody #ruvic-demo .stp-nm{color:var(--text) !important}\nbody #ruvic-demo .stp-dt{color:var(--text2) !important}\nbody #ruvic-demo .rb-sb-head h3{color:var(--text) !important}\nbody #ruvic-demo .rb-sb-head p{color:var(--text3) !important}\nbody #ruvic-demo .cb-t{color:var(--text) !important}\nbody #ruvic-demo .cb-desc{color:var(--text2) !important}\nbody #ruvic-demo .rb-trk h4{color:var(--text3) !important}\nbody #ruvic-demo .rb-title{color:var(--text) !important}\nbody #ruvic-demo .rb-sub{color:var(--text2) !important}\nbody #ruvic-demo .speed-row label{color:var(--text3) !important}\nbody #ruvic-demo .sv{color:var(--orange) !important}\n\n<\/style>\n\n<div id=\"ruvic-bg\">\n<div id=\"ruvic-demo\" data-theme=\"dark\">\n\n  <header class=\"rb-header\">\n    <button class=\"rb-theme\" id=\"rb-theme\" type=\"button\" aria-label=\"Cambiar tema claro\/oscuro\">\n      <span class=\"knob\"><\/span>\n      <i class=\"moon\">\u263e<\/i>\n      <i class=\"sun\"><svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"display:block\"><circle cx=\"12\" cy=\"12\" r=\"4\"><\/circle><path d=\"M12 2.5v2.2M12 19.3v2.2M5.1 5.1l1.5 1.5M17.4 17.4l1.5 1.5M2.5 12h2.2M19.3 12h2.2M5.1 18.9l1.5-1.5M17.4 6.6l1.5-1.5\"><\/path><\/svg><\/i>\n    <\/button>\n    <span class=\"rb-eyebrow\"><span class=\"pd\"><\/span>Demo interactiva \u00b7 Orquestaci\u00f3n<\/span>\n    <h2 class=\"rb-title\">No te lo contamos: <span class=\"ac\">m\u00edralo fluir en tiempo real<\/span>.<\/h2>\n    <p class=\"rb-sub\">Elige un caso de uso y reproduce el flujo completo de principio a fin: canales, agentes, modelos y tus sistemas, orquestados por Ruvic.<\/p>\n  <\/header>\n\n  <div class=\"rb-widget\" id=\"rb-widget\">\n    <div class=\"rb-canvas-area\" id=\"rb-ca\">\n      <div class=\"rb-zp\" id=\"rb-zp\">\n        <canvas id=\"rb-fc\"><\/canvas>\n        <div class=\"rb-nl\" id=\"rb-nl\"><\/div>\n      <\/div>\n      <div class=\"rb-hint\">Arrastra para mover \u00b7 pellizca para hacer zoom<\/div>\n    <\/div>\n    <aside class=\"rb-sb\">\n      <div class=\"rb-sb-head\">\n        <div class=\"rb-mark\">R<\/div>\n        <div>\n          <h3><b>Ruvic AI<\/b> \u00b7 Casos de uso<\/h3>\n          <p>Haz clic en un canal o elige un caso para ver el flujo de ida y vuelta<\/p>\n        <\/div>\n      <\/div>\n      <div class=\"rb-filter\" id=\"rb-filters\"><\/div>\n      <div class=\"rb-cases\" id=\"rb-cl\"><\/div>\n      <div class=\"rb-trk\" id=\"rb-trk\">\n        <h4>Flujo activo<\/h4>\n        <p class=\"rb-empty\">Selecciona un caso de uso para visualizar cada paso.<\/p>\n      <\/div>\n      <div class=\"rb-ctrls\">\n        <div class=\"rb-ctrls-row\">\n          <button class=\"btn btn-play\" id=\"rb-pb\" type=\"button\" disabled=\"\">Reproducir flujo<\/button>\n          <button class=\"btn btn-rst\" id=\"rb-rst\" type=\"button\">\u21ba Reiniciar<\/button>\n        <\/div>\n        <div class=\"speed-row\">\n          <label for=\"rb-spd\">Velocidad<\/label>\n          <input type=\"range\" min=\"1\" max=\"5\" value=\"3\" id=\"rb-spd\">\n          <span class=\"sv\" id=\"rb-spdV\">3x<\/span>\n        <\/div>\n      <\/div>\n    <\/aside>\n  <\/div>\n<\/div>\n<\/div>\n\n<script>\n(function(){\n\"use strict\";\nconst root=document.getElementById('ruvic-demo');\n\n\/* ---------------- DATOS (sin cambios de contenido) ---------------- *\/\nconst N={\n  'whatsapp':{x:13,y:11,l:'WhatsApp',c:'#25D366',lt:'W',t:'ch'},\n  'telegram':{x:13,y:25,l:'Telegram',c:'#0088cc',lt:'T',t:'ch'},\n  'email':{x:13,y:40,l:'Correo electr\u00f3nico',c:'#EA4335',lt:'E',t:'ch'},\n  'voice':{x:13,y:54,l:'Voz \/ SIP',c:'#378ADD',lt:'V',t:'ch'},\n  'api':{x:13,y:68,l:'API directa',c:'#4a5568',lt:'{}',t:'ch'},\n  'widget':{x:13,y:81,l:'Widget web',c:'#7c3aed',lt:'JS',t:'ch'},\n\n  'engine':{x:41,y:43,l:'Ruvic AI Engine',c:'#534AB7',lt:'R',t:'core'},\n  'memory':{x:34,y:66,l:'Memoria',c:'#10b981',lt:'M',t:'sub'},\n  'queue':{x:46,y:66,l:'Cola de mensajes',c:'#f97316',lt:'Q',t:'sub'},\n\n  'gpt4o':{x:25,y:84,l:'GPT-4o',c:'#10a37f',lt:'G',t:'llm'},\n  'gemini':{x:35,y:84,l:'Gemini',c:'#4285F4',lt:'G',t:'llm'},\n  'claude':{x:45,y:84,l:'Claude',c:'#d4537e',lt:'C',t:'llm'},\n  'deepseek':{x:55,y:84,l:'DeepSeek',c:'#3B6D11',lt:'D',t:'llm'},\n\n  'agent-conv':{x:68,y:15,l:'Agente conversacional',c:'#10b981',lt:'C',t:'ag'},\n  'agent-voz':{x:68,y:29,l:'Agente de voz',c:'#3b82f6',lt:'V',t:'ag'},\n  'agent-soporte':{x:68,y:43,l:'Agente de soporte',c:'#f97316',lt:'S',t:'ag'},\n  'agent-fact':{x:68,y:58,l:'Agente de facturaci\u00f3n',c:'#eab308',lt:'F',t:'ag'},\n  'agent-anal':{x:68,y:73,l:'Agente de an\u00e1lisis',c:'#8b5cf6',lt:'A',t:'ag'},\n\n  'crm':{x:87,y:11,l:'CRM',c:'#3b82f6',t:'cn',sub:'Salesforce, HubSpot'},\n  'erp':{x:87,y:25,l:'ERP',c:'#3b82f6',t:'cn',sub:'SAP, Dynamics 365'},\n  'ticketing':{x:87,y:40,l:'Mesa de ayuda',c:'#3b82f6',t:'cn',sub:'Jira, Freshdesk'},\n  'fact-elec':{x:87,y:54,l:'Facturaci\u00f3n electr\u00f3nica',c:'#ef4444',t:'cn',sub:'DIAN, SII, SUNAT'},\n  'google-ws':{x:87,y:68,l:'Google Workspace',c:'#3b82f6',t:'cn',sub:'Sheets, Drive, Calendar'},\n  'slack':{x:87,y:82,l:'Slack \/ Teams',c:'#3b82f6',t:'cn',sub:'Notificaciones'},\n\n  'postgresql':{x:13,y:95,l:'PostgreSQL',c:'#10b981',t:'dt'},\n  'mongodb':{x:27,y:95,l:'MongoDB',c:'#10b981',t:'dt'},\n  'redis':{x:41,y:95,l:'Redis',c:'#10b981',t:'dt'},\n  'archivos':{x:56,y:95,l:'Archivos',c:'#f97316',t:'dt'},\n  'storage':{x:71,y:95,l:'Almacenamiento',c:'#10b981',t:'dt'},\n  'audio':{x:87,y:95,l:'Audio',c:'#f97316',t:'dt'},\n};\n\nconst CS=[\n{id:'wa-sup',ch:'whatsapp',t:'Soporte al cliente v\u00eda WhatsApp',d:'Un cliente consulta el estado de su pedido. Ruvic busca en el CRM y responde autom\u00e1ticamente.',kpi:'Reduce tiempo de respuesta un 60%',\n path:['whatsapp','engine','memory','claude','agent-conv','crm','agent-conv','engine','whatsapp'],\n steps:[\n  {n:'WhatsApp',dt:'El cliente env\u00eda: \"\u00bfD\u00f3nde est\u00e1 mi pedido #4521?\"',c:'#25D366',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica la intenci\u00f3n: consulta de estado de pedido',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Recupera el contexto previo del cliente',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'Genera una consulta estructurada para el CRM',c:'#d4537e',dir:'out'},\n  {n:'Agente conversacional',dt:'Ejecuta la consulta y formatea la respuesta',c:'#10b981',dir:'out'},\n  {n:'CRM',dt:'Salesforce retorna: pedido en camino, llega ma\u00f1ana',c:'#3b82f6',dir:'ret'},\n  {n:'Agente conversacional',dt:'Compone respuesta amigable para el cliente',c:'#10b981',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Valida la respuesta y la enruta al canal de salida',c:'#534AB7',dir:'ret'},\n  {n:'WhatsApp',dt:'Responde: \"Tu pedido #4521 est\u00e1 en camino \\uD83D\\uDCE6\"',c:'#25D366',dir:'ret'},\n]},\n{id:'wa-tkt',ch:'whatsapp',t:'Crear ticket desde WhatsApp',d:'Un cliente reporta un problema t\u00e9cnico. Ruvic crea un ticket en Jira autom\u00e1ticamente.',kpi:'Reduce creaci\u00f3n de tickets un 55%',\n path:['whatsapp','engine','memory','gpt4o','agent-soporte','ticketing','agent-soporte','engine','whatsapp'],\n steps:[\n  {n:'WhatsApp',dt:'El cliente escribe: \"Mi factura tiene un error en el monto\"',c:'#25D366',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como incidencia t\u00e9cnica, prioridad media',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Carga el historial de tickets previos del cliente',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Extrae detalles: tipo de error, n\u00famero de factura, monto',c:'#10a37f',dir:'out'},\n  {n:'Agente de soporte',dt:'Formatea el ticket con los campos requeridos',c:'#f97316',dir:'out'},\n  {n:'Mesa de ayuda',dt:'Jira crea ticket BILL-892: \"Error en factura #1204\"',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de soporte',dt:'Confirma la creaci\u00f3n y obtiene n\u00famero de ticket',c:'#f97316',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Enruta la confirmaci\u00f3n al canal original',c:'#534AB7',dir:'ret'},\n  {n:'WhatsApp',dt:'Responde: \"Ticket BILL-892 creado, te notificaremos\"',c:'#25D366',dir:'ret'},\n]},\n{id:'tg-info',ch:'telegram',t:'Consulta de informaci\u00f3n por Telegram',d:'Un empleado consulta pol\u00edticas internas. Ruvic busca en la base de conocimiento.',kpi:'Ahorra 40 min diarios por empleado',\n path:['telegram','engine','memory','gemini','agent-conv','google-ws','agent-conv','engine','telegram'],\n steps:[\n  {n:'Telegram',dt:'El empleado pregunta: \"\u00bfCu\u00e1l es la pol\u00edtica de vacaciones?\"',c:'#0088cc',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como consulta interna, base de conocimiento',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Identifica al empleado y sus permisos de acceso',c:'#10b981',dir:'out'},\n  {n:'Gemini',dt:'Realiza b\u00fasqueda sem\u00e1ntica en documentos corporativos',c:'#4285F4',dir:'out'},\n  {n:'Agente conversacional',dt:'Procesa el resultado y extrae la secci\u00f3n relevante',c:'#10b981',dir:'out'},\n  {n:'Google Workspace',dt:'Drive retorna: Pol\u00edtica_RRHH_2026.pdf, p\u00e1gina 12',c:'#3b82f6',dir:'ret'},\n  {n:'Agente conversacional',dt:'Resume la pol\u00edtica en lenguaje claro',c:'#10b981',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Formatea la respuesta y la enruta',c:'#534AB7',dir:'ret'},\n  {n:'Telegram',dt:'Responde con el resumen y un enlace al documento',c:'#0088cc',dir:'ret'},\n]},\n{id:'em-inv',ch:'email',t:'Procesamiento autom\u00e1tico de facturas',d:'Ruvic recibe una factura por correo, la valida y la registra en el sistema contable.',kpi:'Reduce errores de facturaci\u00f3n un 80%',\n path:['email','engine','memory','claude','agent-fact','fact-elec','agent-fact','engine','email'],\n steps:[\n  {n:'Correo electr\u00f3nico',dt:'El proveedor env\u00eda una factura adjunta en PDF',c:'#EA4335',dir:'out'},\n  {n:'Ruvic Engine',dt:'Detecta el adjunto PDF y lo clasifica como factura',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Verifica al proveedor en la base de datos',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'OCR y extracci\u00f3n: NIT, monto, \u00edtems, impuestos',c:'#d4537e',dir:'out'},\n  {n:'Agente de facturaci\u00f3n',dt:'Valida los datos fiscales contra las reglas de la DIAN',c:'#eab308',dir:'out'},\n  {n:'Facturaci\u00f3n electr\u00f3nica',dt:'La DIAN valida y registra la factura electr\u00f3nica',c:'#ef4444',dir:'ret'},\n  {n:'Agente de facturaci\u00f3n',dt:'Registra en el sistema contable y genera el asiento',c:'#eab308',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Prepara la confirmaci\u00f3n con el n\u00famero de radicado',c:'#534AB7',dir:'ret'},\n  {n:'Correo electr\u00f3nico',dt:'Responde: \"Factura FE-2026-4521 radicada con \u00e9xito\"',c:'#EA4335',dir:'ret'},\n]},\n{id:'vz-cc',ch:'voice',t:'Centro de llamadas inteligente',d:'Una llamada de cliente se transcribe en tiempo real. Ruvic resuelve sin agente humano.',kpi:'Reduce tiempos de espera un 60%',\n path:['voice','engine','memory','deepseek','agent-voz','crm','agent-voz','engine','voice'],\n steps:[\n  {n:'Voz \/ SIP',dt:'El cliente llama: audio en streaming v\u00eda WebSocket',c:'#378ADD',dir:'out'},\n  {n:'Ruvic Engine',dt:'Transcripci\u00f3n en tiempo real (STT), clasifica intenci\u00f3n',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Identifica al cliente por n\u00famero, carga su perfil',c:'#10b981',dir:'out'},\n  {n:'DeepSeek',dt:'Analiza la intenci\u00f3n: cambio de plan de servicio',c:'#3B6D11',dir:'out'},\n  {n:'Agente de voz',dt:'Consulta los planes disponibles seg\u00fan el perfil',c:'#3b82f6',dir:'out'},\n  {n:'CRM',dt:'Retorna: plan actual Bronce, elegible para Plata',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de voz',dt:'Genera respuesta de voz (TTS) con las opciones',c:'#3b82f6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Env\u00eda el audio de respuesta en streaming',c:'#534AB7',dir:'ret'},\n  {n:'Voz \/ SIP',dt:'El cliente escucha las opciones y confirma el cambio',c:'#378ADD',dir:'ret'},\n]},\n{id:'api-an',ch:'api',t:'An\u00e1lisis de datos v\u00eda API',d:'Un sistema externo solicita un reporte. Ruvic consulta la base de datos y retorna JSON.',kpi:'Genera reportes en 3 segundos',\n path:['api','engine','memory','gpt4o','agent-anal','postgresql','agent-anal','engine','api'],\n steps:[\n  {n:'API directa',dt:'GET \/analytics\/ventas?periodo=Q1-2026',c:'#4a5568',dir:'out'},\n  {n:'Ruvic Engine',dt:'Autentica la API key, clasifica como consulta anal\u00edtica',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Cach\u00e9: verifica si hay un reporte reciente en Redis',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Genera una consulta SQL optimizada para el reporte',c:'#10a37f',dir:'out'},\n  {n:'Agente de an\u00e1lisis',dt:'Ejecuta la consulta con par\u00e1metros seguros',c:'#8b5cf6',dir:'out'},\n  {n:'PostgreSQL',dt:'Retorna 1.247 registros de ventas del Q1',c:'#10b981',dir:'ret'},\n  {n:'Agente de an\u00e1lisis',dt:'Procesa, agrega, calcula KPIs y tendencias',c:'#8b5cf6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Formatea la respuesta JSON estructurada',c:'#534AB7',dir:'ret'},\n  {n:'API directa',dt:'Retorna: {ingresos: $142K, crecimiento: +23%}',c:'#4a5568',dir:'ret'},\n]},\n{id:'wg-lead',ch:'widget',t:'Captura de prospectos desde el sitio web',d:'Un visitante chatea en el widget. Ruvic califica al prospecto y lo registra en HubSpot.',kpi:'Aumenta conversi\u00f3n de leads un 35%',\n path:['widget','engine','memory','gemini','agent-conv','crm','agent-conv','engine','widget'],\n steps:[\n  {n:'Widget web',dt:'El visitante escribe: \"Quiero conocer los precios\"',c:'#7c3aed',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como prospecto potencial, inicia calificaci\u00f3n',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Nuevo visitante, se crea un perfil temporal',c:'#10b981',dir:'out'},\n  {n:'Gemini',dt:'Genera preguntas de calificaci\u00f3n BANT',c:'#4285F4',dir:'out'},\n  {n:'Agente conversacional',dt:'Conversa: tama\u00f1o de empresa, presupuesto, plazo',c:'#10b981',dir:'out'},\n  {n:'CRM',dt:'HubSpot: crea contacto y oportunidad, puntaje 78\/100',c:'#3b82f6',dir:'ret'},\n  {n:'Agente conversacional',dt:'Agenda una demostraci\u00f3n con el equipo de ventas',c:'#10b981',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Notifica al equipo de ventas v\u00eda Slack',c:'#534AB7',dir:'ret'},\n  {n:'Widget web',dt:'Responde: \"Demo agendada para el jueves a las 2 p.m.\"',c:'#7c3aed',dir:'ret'},\n]},\n{id:'wa-fac',ch:'whatsapp',t:'Consulta de facturaci\u00f3n por WhatsApp',d:'Un cliente solicita copia de su factura. Ruvic la busca y la env\u00eda como PDF.',kpi:'Respuesta en menos de 10 segundos',\n path:['whatsapp','engine','memory','gpt4o','agent-fact','fact-elec','agent-fact','engine','whatsapp'],\n steps:[\n  {n:'WhatsApp',dt:'El cliente escribe: \"Necesito mi factura de febrero\"',c:'#25D366',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como solicitud de documento de facturaci\u00f3n',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Identifica al cliente, NIT e historial de facturas',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Interpreta \"febrero\" como el rango 2026-02-01 a 2026-02-28',c:'#10a37f',dir:'out'},\n  {n:'Agente de facturaci\u00f3n',dt:'Busca la factura en el sistema de facturaci\u00f3n',c:'#eab308',dir:'out'},\n  {n:'Facturaci\u00f3n electr\u00f3nica',dt:'Retorna el PDF de la factura FE-2026-0287',c:'#ef4444',dir:'ret'},\n  {n:'Agente de facturaci\u00f3n',dt:'Prepara el archivo para env\u00edo por WhatsApp',c:'#eab308',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Enruta el documento al canal de salida',c:'#534AB7',dir:'ret'},\n  {n:'WhatsApp',dt:'Env\u00eda el PDF y el mensaje: \"Aqu\u00ed est\u00e1 tu factura \\uD83D\\uDCC4\"',c:'#25D366',dir:'ret'},\n]},\n{id:'em-rh',ch:'email',t:'Gesti\u00f3n de recursos humanos automatizada',d:'Un empleado solicita un permiso por correo. Ruvic lo valida, aprueba y notifica.',kpi:'Aprobaci\u00f3n en menos de 1 minuto',\n path:['email','engine','memory','claude','agent-soporte','google-ws','agent-soporte','engine','email'],\n steps:[\n  {n:'Correo electr\u00f3nico',dt:'El empleado solicita permiso para el viernes 21',c:'#EA4335',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como solicitud de RRHH, tipo permiso',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Verifica el saldo de permisos del empleado',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'Valida la pol\u00edtica: tiene 3 d\u00edas disponibles',c:'#d4537e',dir:'out'},\n  {n:'Agente de soporte',dt:'Crea la solicitud formal y la env\u00eda al aprobador',c:'#f97316',dir:'out'},\n  {n:'Google Workspace',dt:'Calendar: verifica conflictos, registra la ausencia',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de soporte',dt:'Registra la aprobaci\u00f3n autom\u00e1tica (pol\u00edtica cumplida)',c:'#f97316',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Genera la confirmaci\u00f3n y las notificaciones',c:'#534AB7',dir:'ret'},\n  {n:'Correo electr\u00f3nico',dt:'Responde: \"Permiso aprobado. Saldo restante: 2 d\u00edas\"',c:'#EA4335',dir:'ret'},\n]},\n{id:'tg-sec',ch:'telegram',t:'Monitoreo de seguridad proactivo',d:'Ruvic detecta una anomal\u00eda en los logs, la analiza y alerta al equipo v\u00eda Telegram.',kpi:'Reduce incidentes de seguridad un 50%',\n path:['api','engine','memory','deepseek','agent-anal','postgresql','agent-anal','engine','telegram'],\n steps:[\n  {n:'API (webhook)',dt:'Alerta autom\u00e1tica: m\u00e1s de 50 intentos de inicio de sesi\u00f3n fallidos',c:'#4a5568',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como incidente de seguridad, prioridad alta',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Correlaciona con incidentes previos de la misma IP',c:'#10b981',dir:'out'},\n  {n:'DeepSeek',dt:'Analiza el patr\u00f3n: fuerza bruta desde la IP 45.33.x.x',c:'#3B6D11',dir:'out'},\n  {n:'Agente de an\u00e1lisis',dt:'Consulta logs detallados y geolocaliza la IP',c:'#8b5cf6',dir:'out'},\n  {n:'PostgreSQL',dt:'Retorna: 847 intentos en 10 minutos, origen Rusia',c:'#10b981',dir:'ret'},\n  {n:'Agente de an\u00e1lisis',dt:'Genera reporte del incidente con recomendaciones',c:'#8b5cf6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Bloquea la IP autom\u00e1ticamente, prepara la alerta',c:'#534AB7',dir:'ret'},\n  {n:'Telegram',dt:'Alerta al equipo: \"\\uD83D\\uDEA8 IP bloqueada, ver reporte adjunto\"',c:'#0088cc',dir:'ret'},\n]}\n];\n\nconst CHANNELS=[\n  {id:'all',l:'Todos',c:'#6b7280'},\n  {id:'whatsapp',l:'WhatsApp',c:'#25D366'},\n  {id:'telegram',l:'Telegram',c:'#0088cc'},\n  {id:'email',l:'Correo',c:'#EA4335'},\n  {id:'voice',l:'Voz',c:'#378ADD'},\n  {id:'api',l:'API',c:'#4a5568'},\n  {id:'widget',l:'Widget',c:'#7c3aed'},\n];\n\n\/* ---------------- ESTADO ---------------- *\/\nlet ac=null,anim=false,cs=0,dots=[],hl=new Set(),W,H,cvs,ctx,filt='all',spd=3,advTmr=null,isNarrow=false;\nconst $=id=>root.querySelector('#'+id);\nconst widget=$('rb-widget'),ca=$('rb-ca'),zp=$('rb-zp');\n\nfunction lineIdle(){return root.dataset.theme==='light'?'rgba(34,38,71,0.14)':'rgba(250,240,228,0.12)';}\n\n\/* ---------------- INIT ---------------- *\/\nfunction init(){\n  cvs=$('rb-fc');ctx=cvs.getContext('2d');\n  renderFilters();renderCases();\n  \/\/ Doble rAF: garantiza que el browser ya calcul\u00f3 dimensiones reales (importante en WP)\n  requestAnimationFrame(()=>requestAnimationFrame(applyLayout));\n  window.addEventListener('load',applyLayout);\n  \/\/ listeners\n  $('rb-pb').addEventListener('click',play);\n  $('rb-rst').addEventListener('click',reset);\n  $('rb-spd').addEventListener('input',updSpd);\n  $('rb-theme').addEventListener('click',toggleTheme);\n  ca.addEventListener('click',e=>{ if(!didPan ? (e.target===cvs ? true : e.target===ca ? true : e.target===zp) : false) reset(); });\n  \/\/ tema guardado\n  try{const sv=localStorage.getItem('ruvicTheme');if(sv)root.dataset.theme=sv;}catch(e){}\n  \/\/ decidir layout: load + resize + orientationchange (+ ResizeObserver si est\u00e1 disponible)\n  let rt;\n  window.addEventListener('resize',()=>{clearTimeout(rt);rt=setTimeout(applyLayout,120);});\n  window.addEventListener('orientationchange',()=>setTimeout(applyLayout,250));\n  if(window.ResizeObserver){let raf;new ResizeObserver(()=>{cancelAnimationFrame(raf);raf=requestAnimationFrame(applyLayout);}).observe(widget);}\n  setupTouch();\n  requestAnimationFrame(dr);\n}\n\nfunction toggleTheme(){\n  const next=root.dataset.theme==='light'?'dark':'light';\n  root.dataset.theme=next;\n  try{localStorage.setItem('ruvicTheme',next);}catch(e){}\n}\n\n\/* ---------------- LAYOUT (desktop vs m\u00f3vil) ---------------- *\/\nfunction applyLayout(){\n  isNarrow=widget.clientWidth<760;\n  root.classList.toggle('is-narrow',isNarrow);\n  root.classList.toggle('is-xnarrow',widget.clientWidth<440);\n  rsz();renderNodes();\n  if(isNarrow){recalcZoom();}else{resetTransform();}\n}\n\nfunction rsz(){\n  const dp=window.devicePixelRatio ? window.devicePixelRatio : 1;\n  if(isNarrow){W=1400;H=900;}\n  else{W=ca.clientWidth;H=ca.clientHeight;}\n  cvs.width=W*dp;cvs.height=H*dp;\n  cvs.style.width=W+'px';cvs.style.height=H+'px';\n  const nl=$('rb-nl');\n  nl.style.width=W+'px';nl.style.height=H+'px';\n  zp.style.width=W+'px';zp.style.height=H+'px';\n  ctx.setTransform(dp,0,0,dp,0,0);\n}\n\nfunction p(id){const n=N[id];return{x:n.x\/100*W,y:n.y\/100*H};}\n\n\/* ---------------- RENDER: filtros \/ casos ---------------- *\/\nfunction renderFilters(){\n  $('rb-filters').innerHTML=CHANNELS.map(c=>\n    `<button class=\"fb${filt===c.id?' act':''}\" data-f=\"${c.id}\" type=\"button\"\n       style=\"${filt===c.id?'background:'+c.c+';color:#fff;border-color:'+c.c:''}\">${c.l}<\/button>`).join('');\n  $('rb-filters').querySelectorAll('.fb').forEach(b=>b.addEventListener('click',()=>setFilt(b.dataset.f)));\n}\nfunction setFilt(f){\n  filt=f;renderFilters();\n  if(f==='all'){renderCases();return;}\n  const m=CS.filter(c=>c.ch===f);if(m.length)sel(CS.indexOf(m[0]));else renderCases();\n}\n\nfunction renderCases(){\n  const el=$('rb-cl');\n  const filtered=filt==='all'?CS:CS.filter(c=>c.ch===filt);\n  if(!filtered.length){el.innerHTML='<p class=\"rb-empty\" style=\"padding:18px;text-align:center\">No hay casos para este canal<\/p>';return;}\n  el.innerHTML=filtered.map(c=>{\n    const ri=CS.indexOf(c);const ch=N[c.path[0]];\n    return`<button class=\"cb${(ac ? ac.id===c.id : false) ? ' act' : ''}\" data-i=\"${ri}\" type=\"button\" style=\"--cbc:${ch.c}\">\n      <div class=\"cb-ch\"><span class=\"d\" style=\"background:${ch.c}\"><\/span>${ch.l}<\/div>\n      <div class=\"cb-t\">${c.t}<\/div>\n      <div class=\"cb-desc\">${c.d}<\/div>\n      <div class=\"cb-kpi\">\u25b2 ${c.kpi}<\/div>\n    <\/button>`;}).join('');\n  el.querySelectorAll('.cb').forEach(b=>b.addEventListener('click',()=>sel(+b.dataset.i)));\n}\n\n\/* ---------------- RENDER: nodos ---------------- *\/\nfunction renderNodes(){\n  const ly=$('rb-nl');ly.innerHTML='';\n  const labels=[\n    {t:'Canales',x:13,y:1.5},{t:'Ruvic Engine',x:41,y:1.5},\n    {t:'Orquestaci\u00f3n',x:68,y:1.5},{t:'Conectores',x:88,y:1.5},\n    {t:'Datos \u00b7 Archivos \u00b7 Almacenamiento',x:50,y:89}\n  ];\n  labels.forEach(l=>{\n    const e=document.createElement('div');e.className='sl';\n    e.style.cssText=`left:${l.x}%;top:${l.y}%;transform:translateX(-50%)`;e.textContent=l.t;ly.appendChild(e);\n  });\n\n  Object.entries(N).forEach(([id,n])=>{\n    const e=document.createElement('div');\n    const dim=(hl.size>0 ? !hl.has(id) : false) ? ' dim' : '';\n    const hlc=hl.has(id)?' hl':'';\n    const clk=n.t==='ch'?' clk':'';\n    e.className='nd'+dim+hlc+clk;e.id='rb-nd-'+id;\n    let gc='';\n    if(hl.has(id)){\n      if(n.t==='ch')gc='gt';else if(n.t==='core' ? true : n.t==='sub' ? true : n.t==='llm')gc='gp';\n      else if(n.t==='ag')gc='go';else if(n.t==='cn')gc=n.c==='#ef4444'?'gr':'gb';else gc='gb';\n    }\n    e.style.cssText=`left:${n.x}%;top:${n.y}%;transform:translate(-50%,-50%)`;\n    \/\/ Icono como <canvas>: caja de color + letra se DIBUJAN como p\u00edxeles.\n    \/\/ Los p\u00edxeles de un canvas son 100% inmunes al CSS de Kadence Y a cualquier\n    \/\/ plugin de WordPress (lazy-load, optimizador de im\u00e1genes, sanitizador, CSP).\n    \/\/ Es la \u00fanica t\u00e9cnica que no puede fallar por configuraci\u00f3n externa.\n    function svgIc(icId,color,letter,w,h,rx,fs,cls){\n      return `<canvas id=\"rb-ic-${icId}\" class=\"${cls}\" data-w=\"${w}\" data-h=\"${h}\" data-rx=\"${rx}\" data-fs=\"${fs}\" data-color=\"${color}\" data-letter=\"${letter}\"><\/canvas>`;\n    }\n    if(n.t==='core'){\n      e.innerHTML=`<div class=\"nc nc-core ${gc}\">${svgIc(id,n.c,n.lt,48,48,12,20,'ic ic-lg')}<div class=\"nt nt-lg\">${n.l}<\/div><div class=\"ns\">Orquestaci\u00f3n multi-agente<\/div><div style=\"display:flex;gap:5px;margin-top:8px;flex-wrap:wrap;justify-content:center\"><span class=\"tg\" style=\"background:rgba(139,128,255,.22);color:#a59cff\">Clasificador<\/span><span class=\"tg\" style=\"background:rgba(139,128,255,.22);color:#a59cff\">Enrutador LLM<\/span><span class=\"tg\" style=\"background:rgba(16,185,129,.22);color:#34d399\">Contexto<\/span><\/div><\/div>`;\n    }else if(n.t==='ch'){\n      e.addEventListener('click',()=>filterCh(id));\n      e.innerHTML=`<div class=\"nc ${gc}\">${svgIc(id,n.c,n.lt,36,36,18,13,'ic')}<div class=\"nt\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='ag'){\n      e.innerHTML=`<div class=\"nc ${gc}\">${svgIc(id,n.c,n.lt,36,36,18,13,'ic')}<div class=\"nt\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='sub' ? true : n.t==='llm'){\n      e.innerHTML=`<div class=\"ng ${gc}\" style=\"text-align:center\">${svgIc(id,n.c,n.lt,30,30,8,14,'ic-sm')}<div class=\"nt\" style=\"font-size:10.5px;margin-top:5px\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='cn'){\n      e.innerHTML=`<div class=\"nc ${gc}\" style=\"min-width:128px\"><div class=\"nt\">${n.l}<\/div>${n.sub?'<div class=\"ns\">'+n.sub+'<\/div>':''}<\/div>`;\n    }else{\n      e.innerHTML=`<div class=\"ng ${gc}\" style=\"min-width:auto;white-space:nowrap\"><div class=\"nt\" style=\"font-size:11px\">${n.l}<\/div><\/div>`;\n    }\n    ly.appendChild(e);\n  });\n  \/\/ Dibuja cada icono en su canvas (caja + letra como p\u00edxeles, inmune a CSS\/plugins)\n  ly.querySelectorAll('canvas[data-letter]').forEach(drawIc);\n}\n\n\/* Dibuja un icono (rect redondeado + letra blanca) en un <canvas> *\/\nfunction drawIc(cv){\n  const w=+cv.dataset.w,h=+cv.dataset.h,rx=Math.min(+cv.dataset.rx,w\/2,h\/2),fs=+cv.dataset.fs;\n  const color=cv.dataset.color,letter=cv.dataset.letter;\n  const dpr=window.devicePixelRatio||1;\n  cv.width=Math.round(w*dpr);cv.height=Math.round(h*dpr);\n  cv.style.width=w+'px';cv.style.height=h+'px';\n  const x=cv.getContext('2d');\n  x.scale(dpr,dpr);\n  x.clearRect(0,0,w,h);\n  \/\/ rect redondeado\n  x.beginPath();\n  x.moveTo(rx,0);\n  x.arcTo(w,0,w,h,rx);\n  x.arcTo(w,h,0,h,rx);\n  x.arcTo(0,h,0,0,rx);\n  x.arcTo(0,0,w,0,rx);\n  x.closePath();\n  x.fillStyle=color;x.fill();\n  \/\/ letra blanca centrada\n  x.fillStyle='#ffffff';\n  x.font='800 '+fs+'px system-ui,-apple-system,\"Segoe UI\",sans-serif';\n  x.textAlign='center';x.textBaseline='middle';\n  x.fillText(letter,w\/2,h\/2+0.5);\n}\n\n\/* ---------------- RENDER: tracker ---------------- *\/\nfunction renderSteps(c){\n  const t=$('rb-trk');\n  t.innerHTML=`<h4>Flujo activo <span>0 \/ ${c.steps.length}<\/span><\/h4>`+\n    c.steps.map((s,i)=>`<div class=\"stp\" id=\"rb-s-${i}\"><div class=\"stp-n\" id=\"rb-sn-${i}\" style=\"background:${s.c}\">${i+1}<\/div><div class=\"stp-i\"><div class=\"stp-nm\">${s.dir==='ret'?'\u2190 ':'\u2192 '}${s.n}<\/div><div class=\"stp-dt\">${s.dt}<\/div><\/div><\/div>`).join('');\n}\n\n\/* ---------------- INTERACCI\u00d3N ---------------- *\/\nfunction sel(i){\n  if(advTmr){clearTimeout(advTmr);advTmr=null;}\n  ac=CS[i];cs=0;dots=[];anim=false;\n  hl=new Set(ac.path);renderNodes();renderSteps(ac);renderCases();\n  $('rb-pb').disabled=false;\n}\nfunction filterCh(id){\n  filt=id;renderFilters();renderCases();\n  const m=CS.filter(c=>c.ch===id);if(m.length)sel(CS.indexOf(m[0]));\n}\nfunction updSpd(){spd=+$('rb-spd').value;$('rb-spdV').textContent=spd+'x';}\n\nfunction play(){\n  if(!ac ? true : anim)return;anim=true;cs=0;dots=[];\n  $('rb-pb').disabled=true;advance();\n}\nfunction advance(){\n  if(!ac ? true : cs>=ac.path.length-1){anim=false;$('rb-pb').disabled=false;return;}\n  const se=$('rb-s-'+cs);\n  if(se){\n    se.classList.add('on');\n    const trk=$('rb-trk');\n    trk.scrollTo({top:Math.max(0,se.offsetTop-trk.offsetTop-18),behavior:'smooth'});\n  }\n  for(let i=0;i<cs;i++){const pe=$('rb-s-'+i);if(pe){pe.classList.remove('on');pe.classList.add('dn');}}\n  const h4=$('rb-trk').querySelector('h4 span');if(h4)h4.textContent=(cs+1)+' \/ '+ac.steps.length;\n  const icEl=$('rb-ic-'+ac.path[cs]);\n  if(icEl){icEl.classList.remove('pulse');void icEl.offsetWidth;icEl.classList.add('pulse');}\n  const snEl=$('rb-sn-'+cs);\n  if(snEl){snEl.classList.remove('pulse');void snEl.offsetWidth;snEl.classList.add('pulse');}\n\n  const p1=p(ac.path[cs]),p2=p(ac.path[cs+1]);\n  const dir=ac.steps[cs]?ac.steps[cs].dir:'out';\n  const col=dir==='ret'?'#3b82f6':(ac.steps[cs]?ac.steps[cs].c:'#534AB7');\n  dots.push({x1:p1.x,y1:p1.y,x2:p2.x,y2:p2.y,t:0,sp:0.012*spd,c:col,a:true});\n  cs++;\n  advTmr=setTimeout(advance,Math.max(300,800\/spd));\n}\nfunction reset(){\n  if(advTmr){clearTimeout(advTmr);advTmr=null;}\n  ac=null;anim=false;cs=0;dots=[];hl.clear();filt='all';\n  renderFilters();renderCases();renderNodes();\n  $('rb-pb').disabled=true;\n  $('rb-trk').innerHTML='<h4>Flujo activo<\/h4><p class=\"rb-empty\">Selecciona un caso de uso para visualizar cada paso.<\/p>';\n}\n\n\/* ---------------- CANVAS LOOP ---------------- *\/\nfunction dr(){\n  ctx.clearRect(0,0,W,H);\n  if(!ac)drawIdle();else drawActive();\n  dots.forEach(d=>{\n    if(!d.a)return;d.t+=d.sp;if(d.t>=1){d.a=false;return;}\n    const t=d.t,mx=(d.x1+d.x2)\/2,my=(d.y1+d.y2)\/2;\n    const x=(1-t)**2*d.x1+2*(1-t)*t*mx+t**2*d.x2;\n    const y=(1-t)**2*d.y1+2*(1-t)*t*my+t**2*d.y2;\n    ctx.beginPath();ctx.arc(x,y,18,0,Math.PI*2);ctx.fillStyle=hr(d.c,.09);ctx.fill();\n    ctx.beginPath();ctx.arc(x,y,10,0,Math.PI*2);ctx.fillStyle=hr(d.c,.28);ctx.fill();\n    ctx.beginPath();ctx.arc(x,y,5,0,Math.PI*2);ctx.fillStyle=d.c;ctx.fill();\n  });\n  dots=dots.filter(d=>d.a);\n  requestAnimationFrame(dr);\n}\nfunction drawIdle(){\n  const col=lineIdle();\n  \/\/ Canales \u2192 Engine\n  ['whatsapp','telegram','email','voice','api','widget'].forEach(c=>{const a=p(c),b=p('engine');bz(a.x+50,a.y,b.x-90,b.y,col,1.4);});\n  \/\/ Engine \u2192 Agentes\n  ['agent-conv','agent-voz','agent-soporte','agent-fact','agent-anal'].forEach(a=>{const s=p('engine'),e=p(a);bz(s.x+90,s.y,e.x-60,e.y,col,1.4);});\n}\nfunction drawActive(){\n  for(let i=0;i<ac.path.length-1;i++){\n    const a=p(ac.path[i]),b=p(ac.path[i+1]);\n    const done=i<cs,dir=ac.steps[i]?ac.steps[i].dir:'out';\n    const col=dir==='ret'?'#3b82f6':(ac.steps[i]?ac.steps[i].c:'#534AB7');\n    bz(a.x,a.y,b.x,b.y,hr(col,done?.32:.07),done?2.6:1.2);\n  }\n}\nfunction bz(x1,y1,x2,y2,c,w){\n  ctx.beginPath();ctx.moveTo(x1,y1);\n  const mx=(x1+x2)\/2,my=(y1+y2)\/2;\n  ctx.quadraticCurveTo(mx,my,x2,y2);\n  ctx.strokeStyle=c;ctx.lineWidth=w;ctx.stroke();\n}\nfunction hr(h,a){const r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16);return`rgba(${r},${g},${b},${a})`;}\n\n\/* ---------------- ZOOM \/ PAN T\u00c1CTIL (m\u00f3vil) ---------------- *\/\nlet scale=1,tx=0,ty=0,lastDist=0,isPinching=false,isDragging=false,startTx=0,startTy=0,didPan=false;\nfunction applyTransform(){zp.style.transform=`translate(${tx}px,${ty}px) scale(${scale})`;}\nfunction resetTransform(){scale=1;tx=0;ty=0;zp.style.transform='none';}\nfunction recalcZoom(){\n  const cw=ca.clientWidth,ch=ca.clientHeight;\n  scale=Math.min(cw\/1400,ch\/900);\n  tx=(cw-1400*scale)\/2;ty=(ch-900*scale)\/2;\n  applyTransform();\n}\nfunction setupTouch(){\n  if(!('ontouchstart' in window))return;\n  ca.addEventListener('touchstart',e=>{\n    if(!isNarrow)return;\n    if(e.touches.length===2){isPinching=true;isDragging=false;\n      const dx=e.touches[0].clientX-e.touches[1].clientX,dy=e.touches[0].clientY-e.touches[1].clientY;\n      lastDist=Math.hypot(dx,dy);\n    }else if(e.touches.length===1){isDragging=true;didPan=false;\n      startTx=e.touches[0].clientX-tx;startTy=e.touches[0].clientY-ty;}\n  },{passive:true});\n  ca.addEventListener('touchmove',e=>{\n    if(!isNarrow)return;\n    if(e.touches.length===2 ? isPinching : false){e.preventDefault();\n      const dx=e.touches[0].clientX-e.touches[1].clientX,dy=e.touches[0].clientY-e.touches[1].clientY;\n      const dist=Math.hypot(dx,dy),ratio=dist\/lastDist;\n      const ns=Math.min(4,Math.max(0.2,scale*ratio));\n      const rect=ca.getBoundingClientRect();\n      const mx=(e.touches[0].clientX+e.touches[1].clientX)\/2-rect.left;\n      const my=(e.touches[0].clientY+e.touches[1].clientY)\/2-rect.top;\n      tx=mx-(mx-tx)*ns\/scale;ty=my-(my-ty)*ns\/scale;scale=ns;lastDist=dist;applyTransform();\n    }else if(e.touches.length===1 ? isDragging : false){e.preventDefault();didPan=true;\n      tx=e.touches[0].clientX-startTx;ty=e.touches[0].clientY-startTy;applyTransform();}\n  },{passive:false});\n  ca.addEventListener('touchend',e=>{\n    if(e.touches.length<2)isPinching=false;\n    if(e.touches.length===0){isDragging=false;setTimeout(()=>{didPan=false;},50);}\n  },{passive:true});\n}\n\ninit();\n\n\/* Animacion de entrada: revela la seccion al entrar en viewport *\/\n(function(){\n  root.classList.add('rv-anim');\n  function inview(){root.classList.add('rv-in');}\n  if('IntersectionObserver' in window){\n    var io=new IntersectionObserver(function(es){\n      for(var i=0;i<es.length;i++){ if(es[i].isIntersecting){ inview(); io.disconnect(); } }\n    },{threshold:.15});\n    io.observe(root);\n  } else { inview(); }\n  setTimeout(inview,3000); \/* respaldo: nada queda oculto *\/\n})();\n\n\/\/ Forzar estilos del slider que Kadence sobreescribe (solo lo independiente del tema:\n\/\/ borde\/sombra\/padding). El COLOR de fondo lo maneja el CSS por tema para que cambie\n\/\/ correctamente al alternar claro\/oscuro.\n(function(){\n  const rng=root.querySelector('#rb-spd');\n  if(!rng)return;\n  rng.style.setProperty('border','none','important');\n  rng.style.setProperty('box-shadow','none','important');\n  rng.style.setProperty('padding','0','important');\n  rng.style.setProperty('outline','none','important');\n})();\n\n})();\n<\/script>\n\n\n\n<style id=\"ruvic-css-sec\">\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Syne:wght@500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:wght@400;500;600;700');\n@import url('https:\/\/fonts.googleapis.com\/css2?family=JetBrains+Mono:wght@400;500');\n\n\/* ============================================================\n   RUVIC AI \u2014 DEMO INTERACTIVA  \u00b7  bloque WordPress autocontenido\n   Todo el CSS est\u00e1 namespaced bajo #ruvic-demo-sec para no chocar\n   con el tema de WordPress. Toggle claro\/oscuro incluido.\n   ============================================================ *\/\n\n#ruvic-demo-sec, #ruvic-demo-sec *{box-sizing:border-box;margin:0;padding:0;line-height:1.4}\n#ruvic-demo-sec{\n  --font:'Plus Jakarta Sans',system-ui,-apple-system,sans-serif;\n  font-family:var(--font);\n  width:100%;max-width:1400px;margin:0 auto;\n  padding:30px 30px 34px;\n  border-radius:30px;\n  position:relative;\n  -webkit-font-smoothing:antialiased;\n  text-align:left;\n  isolation:isolate;\n}\n#ruvic-demo-sec *{font-family:var(--font)}\n\n\/* Fondo navy profundo que rodea el widget \u2014 se extiende a todo el ancho.\n   La t\u00e9cnica de m\u00e1rgenes negativos lo lleva de borde a borde de la pantalla;\n   si la secci\u00f3n tiene overflow oculto, simplemente queda al ancho del contenido. *\/\n#ruvic-bg-sec{background:#0A0E1F;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);\n  padding:48px clamp(14px,4vw,40px)}\n\n\/* ---------- TEMA OSCURO (por defecto, colores actuales) ---------- *\/\n#ruvic-demo-sec[data-theme=\"dark\"]{\n  --surface:#111b3d; --surface2:#0d1530; --sb:#0f1834; --sb2:rgba(0,0,0,.28);\n  --card-hi:#1b2658; --card:#141e48; --ghost:#172148;\n  --border:rgba(250,240,228,.12); --border2:rgba(250,240,228,.2);\n  --text:#faf0e4; --text2:rgba(250,240,228,.62); --text3:rgba(250,240,228,.34);\n  --red:#ff363a; --orange:#fdaa4c; --purple:#8b80ff;\n  --grid:rgba(250,240,228,.05); --glow:rgba(83,74,183,.30);\n  --shadow:0 36px 70px -28px rgba(0,0,0,.7); --nshadow:0 3px 10px -2px rgba(0,0,0,.4);\n  --kpi-bg:rgba(253,170,76,.16); --kpi-tx:#fdaa4c;\n  background:\n    radial-gradient(130% 90% at 50% -10%, #18244f 0%, #0d1430 52%, #090e22 100%);\n  box-shadow:inset 0 1px 0 rgba(250,240,228,.05);\n}\n\/* ---------- TEMA CLARO (versi\u00f3n white) ---------- *\/\n#ruvic-demo-sec[data-theme=\"light\"]{\n  --surface:#ffffff; --surface2:#f6f8fd; --sb:#ffffff; --sb2:#f6f8fd;\n  --card-hi:#ffffff; --card:#fbfcfe; --ghost:#f1f4fb;\n  --border:rgba(22,26,55,.1); --border2:rgba(22,26,55,.16);\n  --text:#161a33; --text2:rgba(22,26,51,.6); --text3:rgba(22,26,51,.4);\n  --red:#ff363a; --orange:#e8890a; --purple:#534AB7;\n  --grid:rgba(22,26,55,.05); --glow:rgba(83,74,183,.14);\n  --shadow:0 30px 60px -28px rgba(30,40,90,.32); --nshadow:0 6px 16px -8px rgba(30,40,90,.22);\n  --kpi-bg:rgba(232,137,10,.12); --kpi-tx:#c9760a;\n  background:\n    radial-gradient(120% 90% at 50% -10%, #ffffff 0%, #eef1fa 60%, #e6eaf6 100%);\n  box-shadow:inset 0 1px 0 rgba(255,255,255,.6);\n}\n\n\/* ---------------- HEADER ---------------- *\/\n#ruvic-demo-sec .rb-header{position:relative;text-align:center;padding:6px 96px 26px}\n#ruvic-demo-sec .rb-eyebrow{display:inline-flex;align-items:center;gap:9px;font-family:'JetBrains Mono',monospace;font-size:.72rem;font-weight:500;white-space:nowrap;\n  letter-spacing:.14em;color:var(--orange);text-transform:uppercase}\n#ruvic-demo-sec .rb-eyebrow .pd{width:7px;height:7px;border-radius:50%;background:var(--orange);\n  box-shadow:0 0 0 0 rgba(253,170,76,.7);animation:rbPing 1.8s ease-out infinite}\n@keyframes rbPing{0%{box-shadow:0 0 0 0 rgba(253,170,76,.55)}\n  70%{box-shadow:0 0 0 8px transparent}100%{box-shadow:0 0 0 0 transparent}}\n#ruvic-demo-sec .rb-title{margin:16px 0 0;font-family:'Syne',sans-serif;font-size:clamp(1.9rem,3.8vw,3rem);line-height:1.08;font-weight:600;letter-spacing:-.025em;color:var(--text);text-wrap:balance}\n#ruvic-demo-sec .rb-title .ac{color:var(--red)}\n#ruvic-demo-sec .rb-sub{margin:14px auto 0;max-width:600px;font-family:'DM Sans',sans-serif;font-size:1.05rem;line-height:1.6;color:var(--text2);text-wrap:pretty}\n\n\/* Theme toggle *\/\n#ruvic-demo-sec .rb-theme{position:absolute;top:2px;right:0;display:inline-flex;align-items:center;gap:0;\n  background:var(--ghost);border:1px solid var(--border);border-radius:100px;padding:4px;cursor:pointer;\n  user-select:none}\n#ruvic-demo-sec .rb-theme i{width:30px;height:28px;border-radius:100px;display:flex;align-items:center;justify-content:center;\n  font-style:normal;font-size:14px;color:var(--text3);transition:all .25s;position:relative;z-index:1}\n#ruvic-demo-sec .rb-theme .knob{position:absolute;top:4px;left:4px;width:30px;height:28px;border-radius:100px;\n  background:linear-gradient(180deg,var(--red),#e02d31);box-shadow:0 4px 10px -3px var(--red);transition:transform .28s cubic-bezier(.5,1.4,.5,1)}\n#ruvic-demo-sec[data-theme=\"light\"] .rb-theme .knob{transform:translateX(30px)}\n#ruvic-demo-sec[data-theme=\"dark\"] .rb-theme i.moon{color:#fff}\n#ruvic-demo-sec[data-theme=\"light\"] .rb-theme i.sun{color:#fff}\n\n\/* ---------------- WIDGET CARD ---------------- *\/\n#ruvic-demo-sec .rb-widget{position:relative;border-radius:24px;overflow:hidden;height:750px;\n  background:var(--surface);border:1px solid var(--border2);box-shadow:var(--shadow);\n  display:grid;grid-template-columns:1fr 310px}\n#ruvic-demo-sec[data-theme=\"dark\"] .rb-widget::after{content:\"\";position:absolute;inset:0;border-radius:24px;pointer-events:none;\n  box-shadow:inset 0 1px 0 rgba(250,240,228,.08)}\n#ruvic-demo-sec[data-theme=\"light\"] .rb-widget::after{content:\"\";position:absolute;inset:0;border-radius:24px;pointer-events:none;\n  box-shadow:inset 0 1px 0 rgba(22,26,51,.08)}\n\n\/* ---- diagrama (canvas) ---- *\/\n#ruvic-demo-sec .rb-canvas-area{position:relative;overflow:hidden;height:100%;\n  background:\n    radial-gradient(circle at 41% 42%, var(--glow) 0%, transparent 46%),\n    radial-gradient(var(--grid) 1.1px, transparent 1.1px);\n  background-size:auto, 26px 26px;background-color:var(--surface2)}\n#ruvic-demo-sec .rb-zp{position:absolute;top:0;left:0;transform-origin:0 0}\n#ruvic-demo-sec #rbs-fc{position:absolute;top:0;left:0;z-index:1}\n#ruvic-demo-sec .rb-nl{position:absolute;top:0;left:0;z-index:2;pointer-events:none}\n#ruvic-demo-sec .rb-nl>*{pointer-events:auto}\n#ruvic-demo-sec .rb-hint{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);z-index:4;\n  font-size:10.5px;font-weight:600;color:var(--text3);background:var(--sb2);\n  border:1px solid var(--border);padding:5px 12px;border-radius:100px;display:none;pointer-events:none}\n\n\/* ---- sidebar ---- *\/\n#ruvic-demo-sec .rb-sb{background:var(--sb);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;min-height:0}\n#ruvic-demo-sec .rb-sb-head{padding:18px 18px 14px;border-bottom:1px solid var(--border);display:flex;gap:11px;align-items:flex-start}\n#ruvic-demo-sec .rb-mark{width:34px;height:34px;border-radius:10px;flex-shrink:0;display:flex;align-items:center;justify-content:center;\n  font-weight:800;font-size:16px;color:#fff;background:linear-gradient(150deg,var(--red),#b41f5e);\n  box-shadow:0 6px 16px -6px var(--red)}\n#ruvic-demo-sec .rb-sb-head h3{font-size:15px;font-weight:800;color:var(--text);letter-spacing:-.3px;line-height:17px}\n#ruvic-demo-sec .rb-sb-head h3 b{color:var(--red);font-weight:800}\n#ruvic-demo-sec .rb-sb-head p{font-size:10.5px;color:var(--text3);margin-top:4px;line-height:15px}\n#ruvic-demo-sec .rb-filter{padding:11px 18px;border-bottom:1px solid var(--border);display:flex;gap:6px;flex-wrap:wrap}\n#ruvic-demo-sec .rb-filter::-webkit-scrollbar{display:none}\n#ruvic-demo-sec .fb{padding:6px 11px;line-height:14px;border:1px solid var(--border2);border-radius:9px;font-size:10.5px;font-weight:600;cursor:pointer;flex-shrink:0;white-space:nowrap;\n  background:var(--ghost);color:var(--text2);transition:color .15s,border-color .15s,box-shadow .15s;line-height:1}\n#ruvic-demo-sec .fb:hover{border-color:var(--orange);color:var(--orange);box-shadow:none !important}\n#ruvic-demo-sec .fb.act{background:#ff363a !important;color:#fff !important;border-color:#ff363a !important;box-shadow:0 4px 12px -4px #ff363a !important}\n#ruvic-demo-sec .rb-cases{flex:1;overflow-y:auto;padding:12px 14px;min-height:0}\n#ruvic-demo-sec .rb-cases::-webkit-scrollbar, #ruvic-demo-sec .rb-trk::-webkit-scrollbar{width:5px}\n#ruvic-demo-sec .rb-cases::-webkit-scrollbar-thumb, #ruvic-demo-sec .rb-trk::-webkit-scrollbar-thumb{background:var(--border2);border-radius:5px}\n#ruvic-demo-sec .cb{width:100%;text-align:left;padding:12px 14px;border:1.5px solid var(--border);border-radius:13px;\n  background:var(--card);cursor:pointer;margin-bottom:8px;transition:transform .18s,box-shadow .18s,border-color .18s;display:block;position:relative;overflow:hidden}\n#ruvic-demo-sec .cb::before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cbc,var(--red));opacity:0;transition:opacity .2s}\n#ruvic-demo-sec .cb:hover{border-color:var(--orange);transform:translateY(-2px);box-shadow:0 10px 24px -12px rgba(0,0,0,.4) !important}\n#ruvic-demo-sec[data-theme=\"dark\"] .cb.act{border-color:#ff363a !important;background:#1e1d48 !important;box-shadow:0 8px 24px -10px rgba(255,54,58,.6) !important}\n#ruvic-demo-sec[data-theme=\"light\"] .cb.act{border-color:#ff363a !important;background:#fce9e9 !important;box-shadow:0 8px 24px -10px rgba(255,54,58,.6) !important}\n#ruvic-demo-sec .cb.act::before{opacity:1}\n#ruvic-demo-sec .cb-ch{font-size:9px;line-height:12px;font-weight:800;text-transform:uppercase;letter-spacing:1px;color:var(--text3);display:flex;align-items:center;gap:6px}\n#ruvic-demo-sec .cb-ch .d{width:7px;height:7px;border-radius:50%;flex-shrink:0}\n#ruvic-demo-sec .cb-t{font-size:13px;font-weight:700;color:var(--text);line-height:17px;margin-top:5px}\n#ruvic-demo-sec .cb-desc{font-size:11px;color:var(--text2);margin-top:4px;line-height:15px}\n#ruvic-demo-sec .cb-kpi{display:inline-flex;line-height:13px;align-items:center;gap:4px;margin-top:8px;font-size:9.5px;font-weight:800;padding:4px 9px;border-radius:7px;background:var(--kpi-bg);color:var(--kpi-tx)}\n\n\/* tracker *\/\n#ruvic-demo-sec .rb-trk{border-top:1px solid var(--border);padding:14px 18px;background:var(--sb2);max-height:248px;overflow-y:auto}\n#ruvic-demo-sec .rb-trk h4{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:1px;color:var(--text3);margin-bottom:11px;display:flex;justify-content:space-between;align-items:center}\n#ruvic-demo-sec .rb-trk h4 span{color:var(--orange);font-weight:800}\n#ruvic-demo-sec .rb-empty{font-size:11px;color:var(--text3);line-height:17px}\n#ruvic-demo-sec .stp{display:flex;gap:11px;margin-bottom:10px;opacity:.3;transition:opacity .35s,transform .35s}\n#ruvic-demo-sec .stp:last-child{margin-bottom:2px}\n#ruvic-demo-sec .stp.on{opacity:1;transform:translateX(3px)}\n#ruvic-demo-sec .stp.dn{opacity:.5}\n#ruvic-demo-sec .stp-n{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:9.5px;font-weight:800;color:#fff;flex-shrink:0;box-shadow:0 3px 8px -2px rgba(0,0,0,.4)}\n#ruvic-demo-sec .stp-n.pulse{animation:rbPulse .55s ease}\n@keyframes rbPulse{0%{transform:scale(1)}45%{transform:scale(1.32)}100%{transform:scale(1)}}\n#ruvic-demo-sec .stp-i{flex:1;min-width:0}\n#ruvic-demo-sec .stp-nm{font-size:11.5px;font-weight:700;color:var(--text);line-height:15px}\n#ruvic-demo-sec .stp-dt{font-size:10px;color:var(--text2);margin-top:2px;line-height:14px}\n\n\/* controls *\/\n#ruvic-demo-sec .rb-ctrls{padding:12px 18px 16px;border-top:1px solid var(--border);background:var(--sb2)}\n#ruvic-demo-sec .rb-ctrls-row{display:flex;gap:8px;margin-bottom:11px}\n#ruvic-demo-sec .btn{flex:1;padding:11px;border:none;border-radius:11px;font-size:11.5px;font-weight:800;cursor:pointer;transition:color .15s,border-color .15s,box-shadow .15s,filter .15s;display:flex;align-items:center;justify-content:center;gap:6px}\n#ruvic-demo-sec .btn-play{background:linear-gradient(180deg,var(--red),#e02d31);color:#fff;box-shadow:0 8px 18px -8px var(--red);gap:0}\n#ruvic-demo-sec .btn-play::before{content:\"\";display:inline-block;width:0;height:0;border-style:solid;border-width:5px 0 5px 9px;border-color:transparent transparent transparent #fff;margin-right:7px;flex-shrink:0}\n#ruvic-demo-sec .btn-play:hover{filter:brightness(1.06);box-shadow:0 8px 18px -8px #ff363a !important}\n#ruvic-demo-sec .btn-play:disabled{background:var(--ghost);color:var(--text3);cursor:not-allowed;box-shadow:none}\n#ruvic-demo-sec .btn-play:disabled::before{border-left-color:var(--text3)}\n#ruvic-demo-sec .btn-rst{background:var(--ghost);color:var(--text2);border:1px solid var(--border)}\n#ruvic-demo-sec .btn-rst:hover{border-color:var(--border2);color:var(--text);box-shadow:none !important}\n#ruvic-demo-sec .speed-row{display:flex;align-items:center;gap:10px}\n#ruvic-demo-sec .speed-row label{font-size:10.5px;color:var(--text3);font-weight:700;white-space:nowrap}\n#ruvic-demo-sec .speed-row input[type=range]{flex:1;height:6px;-webkit-appearance:none;appearance:none;border-radius:4px;outline:none;background:transparent;border:none !important;box-shadow:none !important;padding:0 !important}\n#ruvic-demo-sec[data-theme=\"dark\"] .speed-row input[type=range]{background-color:#0b1125 !important;border-color:#0b1125 !important}\n#ruvic-demo-sec .speed-row input[type=range]::-webkit-slider-runnable-track{height:6px;border-radius:4px;background:rgba(250,240,228,.25);border:none;box-shadow:none}\n#ruvic-demo-sec[data-theme=\"light\"] .speed-row input[type=range]::-webkit-slider-runnable-track{background:rgba(22,26,51,.15)}\n#ruvic-demo-sec .speed-row input[type=range]::-moz-range-track{height:6px;border-radius:4px;background:rgba(250,240,228,.25);border:none}\n#ruvic-demo-sec[data-theme=\"light\"] .speed-row input[type=range]::-moz-range-track{background:rgba(22,26,51,.15)}\n#ruvic-demo-sec .speed-row input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--orange);cursor:pointer;box-shadow:0 2px 8px -1px var(--orange);margin-top:-6px}\n#ruvic-demo-sec .speed-row input[type=range]::-moz-range-thumb{width:18px;height:18px;border:none;border-radius:50%;background:var(--orange);cursor:pointer;box-shadow:0 2px 8px -1px var(--orange)}\n#ruvic-demo-sec .speed-row .sv{font-size:11px;font-weight:800;color:var(--orange);min-width:24px;text-align:right}\n\n\/* ---------------- NODES ---------------- *\/\n#ruvic-demo-sec .nd{position:absolute;display:flex;flex-direction:column;align-items:center;text-align:center;transition:opacity .5s,filter .5s;cursor:default}\n#ruvic-demo-sec .nd.dim{opacity:.14;filter:grayscale(.85)}\n#ruvic-demo-sec .nd.hl{z-index:5}\n#ruvic-demo-sec .nd.clk{cursor:pointer}\n#ruvic-demo-sec .nc{background:linear-gradient(180deg,var(--card-hi),var(--card));border:1.5px solid var(--border);border-radius:14px;padding:9px 11px;display:flex;flex-direction:column;align-items:center;gap:4px;min-width:104px;transition:border-color .35s,box-shadow .35s,transform .25s;box-shadow:var(--nshadow)}\n#ruvic-demo-sec .nd.clk:hover .nc{transform:translateY(-2px);border-color:var(--orange);box-shadow:none !important}\n#ruvic-demo-sec .nc.gp{box-shadow:0 0 28px var(--glow),var(--nshadow);border-color:#7c74e6}\n#ruvic-demo-sec .nc.gt{box-shadow:0 0 28px rgba(16,185,129,.28),var(--nshadow);border-color:#10b981}\n#ruvic-demo-sec .nc.go{box-shadow:0 0 28px rgba(249,115,22,.28),var(--nshadow);border-color:#f97316}\n#ruvic-demo-sec .nc.gb{box-shadow:0 0 28px rgba(59,130,246,.28),var(--nshadow);border-color:#3b82f6}\n#ruvic-demo-sec .nc.gr{box-shadow:0 0 28px rgba(239,68,68,.28),var(--nshadow);border-color:#ef4444}\n#ruvic-demo-sec .nc-core{border:2.5px solid #7c74e6;box-shadow:0 0 40px var(--glow),0 18px 40px -16px rgba(83,74,183,.5);padding:17px 24px;min-width:208px;border-radius:20px;position:relative}\n\/* Iconos \u2014 ahora son <img> con SVG data-URI: aislados 100% del CSS de Kadence *\/\n#ruvic-demo-sec .ic{width:36px !important;height:36px !important;border-radius:50%;display:block !important;flex-shrink:0;transition:transform .3s;box-shadow:0 5px 14px -5px rgba(0,0,0,.45);max-width:none !important;border:none !important;padding:0 !important;vertical-align:middle}\n#ruvic-demo-sec .ic-lg{width:48px !important;height:48px !important;border-radius:14px}\n#ruvic-demo-sec .ic-sm{width:30px !important;height:30px !important;border-radius:8px;box-shadow:0 3px 8px -3px rgba(0,0,0,.4);display:block !important;margin:0 auto !important;flex-shrink:0;max-width:none !important;border:none !important;padding:0 !important;vertical-align:middle}\n#ruvic-demo-sec .ic.pulse{animation:rbNode .6s ease}\n@keyframes rbNode{0%{transform:scale(1)}40%{transform:scale(1.22)}100%{transform:scale(1)}}\n#ruvic-demo-sec .ng{background:linear-gradient(180deg,var(--card-hi),var(--ghost));border:1px solid var(--border);border-radius:10px;padding:7px 10px;min-width:0;width:auto;transition:border-color .35s,box-shadow .35s;text-align:center;box-shadow:var(--nshadow)}\n#ruvic-demo-sec .ng .nt{font-size:10px;white-space:nowrap;overflow:visible;line-height:13px}\n#ruvic-demo-sec .nt{font-size:12px;font-weight:700;color:var(--text);line-height:15px}\n#ruvic-demo-sec .nt-lg{font-size:16px;white-space:nowrap}\n#ruvic-demo-sec .ns{font-size:10px;color:var(--text2);line-height:13px}\n#ruvic-demo-sec .tg{font-size:8px;padding:3px 8px;border-radius:7px;font-weight:800;letter-spacing:.2px}\n#ruvic-demo-sec .sl{position:absolute;font-size:10px;line-height:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.6px;color:var(--text3);pointer-events:none;white-space:nowrap}\n\n\/* ============ RESPONSIVE \/ M\u00d3VIL \u2014 layout 2 columnas, sin diagrama ============ *\/\n#ruvic-demo-sec.is-narrow{padding:14px 10px 20px;border-radius:22px}\n#ruvic-demo-sec.is-narrow .rb-header{padding:2px 4px 14px}\n#ruvic-demo-sec.is-narrow .rb-title{font-size:22px;letter-spacing:-.5px}\n#ruvic-demo-sec.is-narrow .rb-sub{font-size:13px;margin-top:8px}\n#ruvic-demo-sec.is-narrow .rb-theme{top:0}\n\/* Diagrama arriba, panel 2 columnas abajo *\/\n#ruvic-demo-sec.is-narrow .rb-canvas-area{\n  display:block;height:320px;width:100%;\n  border-bottom:1px solid var(--border);touch-action:none;\n}\n#ruvic-demo-sec.is-narrow .rb-hint{display:block}\n#ruvic-demo-sec.is-narrow .rb-hint{display:none}\n\/* Widget: bloque simple, altura autom\u00e1tica *\/\n#ruvic-demo-sec.is-narrow .rb-widget{display:block;height:auto}\n\/* Sidebar: 2 columnas \u2014 casos | tracker+controles *\/\n#ruvic-demo-sec.is-narrow .rb-sb{\n  display:grid;\n  grid-template-columns:58% 42%;\n  grid-template-rows:auto auto 1fr auto;\n  border-left:none;\n  height:420px;\n}\n#ruvic-demo-sec.is-narrow .rb-sb-head{\n  grid-column:1;grid-row:1;\n  border-right:1px solid var(--border);border-bottom:1px solid var(--border);\n  padding:14px 12px;\n}\n#ruvic-demo-sec.is-narrow .rb-sb-head h3{font-size:13px}\n#ruvic-demo-sec.is-narrow .rb-sb-head p{font-size:10px}\n#ruvic-demo-sec.is-narrow .rb-filter{\n  grid-column:1;grid-row:2;\n  border-right:1px solid var(--border);border-bottom:1px solid var(--border);\n  padding:8px 10px;gap:4px;\n  flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch;\n}\n#ruvic-demo-sec.is-narrow .rb-cases{\n  grid-column:1;grid-row:3;\n  border-right:1px solid var(--border);\n  max-height:175px;flex:none;\n  overflow-y:auto;\n  padding:8px 10px;\n}\n#ruvic-demo-sec.is-narrow .rb-cases .cb{padding:9px 10px;margin-bottom:6px}\n#ruvic-demo-sec.is-narrow .rb-cases .cb-t{font-size:12px}\n#ruvic-demo-sec.is-narrow .rb-cases .cb-desc{font-size:10px}\n#ruvic-demo-sec.is-narrow .rb-trk{\n  grid-column:2;grid-row:1\/4;\n  max-height:none;border-top:none;\n  overflow-y:auto;\n  padding:12px 10px;\n}\n#ruvic-demo-sec.is-narrow .rb-trk h4{font-size:9.5px}\n#ruvic-demo-sec.is-narrow .stp-nm{font-size:10.5px}\n#ruvic-demo-sec.is-narrow .stp-dt{font-size:9px}\n#ruvic-demo-sec.is-narrow .rb-ctrls{\n  grid-column:1\/3;grid-row:4;\n  padding:8px 12px 12px;\n  border-top:1px solid var(--border);\n}\n#ruvic-demo-sec.is-narrow .btn{font-size:10.5px;padding:9px}\n#ruvic-demo-sec.is-narrow .speed-row label{font-size:9.5px}\n#ruvic-demo-sec.is-narrow .sv{font-size:10px}\n\/* Ajuste tipograf\u00eda xnarrow *\/\n#ruvic-demo-sec.is-xnarrow{padding:10px 8px 16px}\n#ruvic-demo-sec.is-xnarrow .rb-title{font-size:19px}\n#ruvic-demo-sec.is-xnarrow .rb-eyebrow{font-size:9px;letter-spacing:1.4px;padding:5px 9px}\n#ruvic-demo-sec.is-xnarrow .rb-sb-head{padding:10px}\n#ruvic-demo-sec.is-xnarrow .rb-theme{transform:scale(.9);transform-origin:top right}\n\n\n\n\/* ============ Animaciones v2 ============ *\/\n\/* Entrada en viewport: cabecera escalonada + widget con lift (gate .rv-anim la pone el JS) *\/\n#ruvic-demo-sec.rv-anim .rb-eyebrow,\n#ruvic-demo-sec.rv-anim .rb-title,\n#ruvic-demo-sec.rv-anim .rb-sub{opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .7s cubic-bezier(.22,1,.36,1)}\n#ruvic-demo-sec.rv-anim .rb-widget{opacity:0;transform:translateY(24px) scale(.985);transition:opacity .7s ease,transform .8s cubic-bezier(.22,1,.36,1)}\n#ruvic-demo-sec.rv-anim .rb-title{transition-delay:.1s}\n#ruvic-demo-sec.rv-anim .rb-sub{transition-delay:.18s}\n#ruvic-demo-sec.rv-anim .rb-widget{transition-delay:.28s}\n#ruvic-demo-sec.rv-anim.rv-in .rb-eyebrow,\n#ruvic-demo-sec.rv-anim.rv-in .rb-title,\n#ruvic-demo-sec.rv-anim.rv-in .rb-sub{opacity:1;transform:none}\n#ruvic-demo-sec.rv-anim.rv-in .rb-widget{opacity:1;transform:none}\n\n\/* Nucleo del engine: respiracion del glow (opacity+transform, barato en GPU) *\/\n#ruvic-demo-sec .nc-core::after{content:\"\";position:absolute;inset:-16px;border-radius:28px;z-index:-1;pointer-events:none;\n  background:radial-gradient(60% 60% at 50% 50%,var(--glow),transparent 72%);\n  animation:rbsBreath 4.2s ease-in-out infinite}\n@keyframes rbsBreath{0%,100%{opacity:.35;transform:scale(.96)}50%{opacity:.85;transform:scale(1.07)}}\n\n\/* Pasos del tracker: entrada con slide+fade *\/\n#ruvic-demo-sec .stp.on{animation:rbsStep .45s cubic-bezier(.22,1,.36,1)}\n@keyframes rbsStep{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(3px)}}\n\n\/* Caso seleccionado: micro-rebote *\/\n#ruvic-demo-sec .cb.act{animation:rbsSel .5s cubic-bezier(.34,1.56,.64,1)}\n@keyframes rbsSel{0%{transform:scale(.985)}60%{transform:scale(1.014)}100%{transform:scale(1)}}\n\n\/* Boton reproducir: barrido de luz al pasar el mouse *\/\n#ruvic-demo-sec .btn-play{position:relative;overflow:hidden}\n#ruvic-demo-sec .btn-play::after{content:\"\";position:absolute;top:0;bottom:0;left:-70%;width:45%;\n  background:linear-gradient(100deg,transparent,rgba(255,255,255,.38),transparent);\n  transform:skewX(-18deg);transition:left .55s ease;pointer-events:none}\n#ruvic-demo-sec .btn-play:hover:not(:disabled)::after{left:130%}\n\n\/* Chips de filtro: feedback al presionar *\/\n#ruvic-demo-sec .fb:active{transform:scale(.94)}\n#ruvic-demo-sec .fb{transition:color .15s,border-color .15s,box-shadow .15s,transform .15s}\n\n\/* Kadence theme overrides *\/\n#ruvic-demo-sec button:hover{box-shadow:none !important}\n#ruvic-demo-sec button{line-height:14px}\n@media (prefers-reduced-motion:reduce){\n  #ruvic-demo-sec *{animation-duration:.001ms!important;transition-duration:.08s!important}\n}\n\n\/* Nuclear reset \u2014 Kadence body\/global-palette color bleed fix\n   \"body #ruvic-demo-sec\" tiene especificidad (0,1,1) y gana a \"body{color:...}\" de Kadence (0,0,1) *\/\nbody #ruvic-demo-sec{color:#faf0e4}\nbody #ruvic-demo-sec[data-theme=\"light\"]{color:#161a33}\nbody #ruvic-demo-sec .nt{color:var(--text) !important}\nbody #ruvic-demo-sec .ns{color:var(--text2) !important}\nbody #ruvic-demo-sec .nt-lg{color:var(--text) !important}\nbody #ruvic-demo-sec .stp-nm{color:var(--text) !important}\nbody #ruvic-demo-sec .stp-dt{color:var(--text2) !important}\nbody #ruvic-demo-sec .rb-sb-head h3{color:var(--text) !important}\nbody #ruvic-demo-sec .rb-sb-head p{color:var(--text3) !important}\nbody #ruvic-demo-sec .cb-t{color:var(--text) !important}\nbody #ruvic-demo-sec .cb-desc{color:var(--text2) !important}\nbody #ruvic-demo-sec .rb-trk h4{color:var(--text3) !important}\nbody #ruvic-demo-sec .rb-title{color:var(--text) !important}\nbody #ruvic-demo-sec .rb-sub{color:var(--text2) !important}\nbody #ruvic-demo-sec .speed-row label{color:var(--text3) !important}\nbody #ruvic-demo-sec .sv{color:var(--orange) !important}\n\n<\/style>\n\n<div id=\"ruvic-bg-sec\">\n<div id=\"ruvic-demo-sec\" data-theme=\"dark\">\n\n  <header class=\"rb-header\">\n    <button class=\"rb-theme\" id=\"rbs-theme\" type=\"button\" aria-label=\"Cambiar tema claro\/oscuro\">\n      <span class=\"knob\"><\/span>\n      <i class=\"moon\">\u263e<\/i>\n      <i class=\"sun\"><svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"display:block\"><circle cx=\"12\" cy=\"12\" r=\"4\"><\/circle><path d=\"M12 2.5v2.2M12 19.3v2.2M5.1 5.1l1.5 1.5M17.4 17.4l1.5 1.5M2.5 12h2.2M19.3 12h2.2M5.1 18.9l1.5-1.5M17.4 6.6l1.5-1.5\"><\/path><\/svg><\/i>\n    <\/button>\n    <span class=\"rb-eyebrow\"><span class=\"pd\"><\/span>Demo interactiva \u00b7 Ciberseguridad<\/span>\n    <h2 class=\"rb-title\">Del evento a la respuesta: <span class=\"ac\">mira el flujo completo<\/span>.<\/h2>\n    <p class=\"rb-sub\">Elige un caso y reproduce c\u00f3mo Ruvic detecta, analiza y responde de principio a fin: canales, agentes, modelos y tus sistemas, orquestados en tiempo real.<\/p>\n  <\/header>\n\n  <div class=\"rb-widget\" id=\"rbs-widget\">\n    <div class=\"rb-canvas-area\" id=\"rbs-ca\">\n      <div class=\"rb-zp\" id=\"rbs-zp\">\n        <canvas id=\"rbs-fc\"><\/canvas>\n        <div class=\"rb-nl\" id=\"rbs-nl\"><\/div>\n      <\/div>\n      <div class=\"rb-hint\">Arrastra para mover \u00b7 pellizca para hacer zoom<\/div>\n    <\/div>\n    <aside class=\"rb-sb\">\n      <div class=\"rb-sb-head\">\n        <div class=\"rb-mark\">R<\/div>\n        <div>\n          <h3><b>Ruvic AI<\/b> \u00b7 Casos de uso<\/h3>\n          <p>Haz clic en un canal o elige un caso para ver el flujo de ida y vuelta<\/p>\n        <\/div>\n      <\/div>\n      <div class=\"rb-filter\" id=\"rbs-filters\"><\/div>\n      <div class=\"rb-cases\" id=\"rbs-cl\"><\/div>\n      <div class=\"rb-trk\" id=\"rbs-trk\">\n        <h4>Flujo activo<\/h4>\n        <p class=\"rb-empty\">Selecciona un caso de uso para visualizar cada paso.<\/p>\n      <\/div>\n      <div class=\"rb-ctrls\">\n        <div class=\"rb-ctrls-row\">\n          <button class=\"btn btn-play\" id=\"rbs-pb\" type=\"button\" disabled=\"\">Reproducir flujo<\/button>\n          <button class=\"btn btn-rst\" id=\"rbs-rst\" type=\"button\">\u21ba Reiniciar<\/button>\n        <\/div>\n        <div class=\"speed-row\">\n          <label for=\"rbs-spd\">Velocidad<\/label>\n          <input type=\"range\" min=\"1\" max=\"5\" value=\"3\" id=\"rbs-spd\">\n          <span class=\"sv\" id=\"rbs-spdV\">3x<\/span>\n        <\/div>\n      <\/div>\n    <\/aside>\n  <\/div>\n<\/div>\n<\/div>\n\n<script>\n(function(){\n\"use strict\";\nconst root=document.getElementById('ruvic-demo-sec');\n\n\/* ---------------- DATOS (sin cambios de contenido) ---------------- *\/\nconst N={\n  'whatsapp':{x:13,y:11,l:'WhatsApp',c:'#25D366',lt:'W',t:'ch'},\n  'telegram':{x:13,y:25,l:'Telegram',c:'#0088cc',lt:'T',t:'ch'},\n  'email':{x:13,y:40,l:'Correo electr\u00f3nico',c:'#EA4335',lt:'E',t:'ch'},\n  'voice':{x:13,y:54,l:'Voz \/ SIP',c:'#378ADD',lt:'V',t:'ch'},\n  'api':{x:13,y:68,l:'API directa',c:'#4a5568',lt:'{}',t:'ch'},\n  'widget':{x:13,y:81,l:'Widget web',c:'#7c3aed',lt:'JS',t:'ch'},\n\n  'engine':{x:41,y:43,l:'Ruvic AI Engine',c:'#534AB7',lt:'R',t:'core'},\n  'memory':{x:34,y:66,l:'Memoria',c:'#10b981',lt:'M',t:'sub'},\n  'queue':{x:46,y:66,l:'Cola de mensajes',c:'#f97316',lt:'Q',t:'sub'},\n\n  'gpt4o':{x:25,y:84,l:'GPT-4o',c:'#10a37f',lt:'G',t:'llm'},\n  'gemini':{x:35,y:84,l:'Gemini',c:'#4285F4',lt:'G',t:'llm'},\n  'claude':{x:45,y:84,l:'Claude',c:'#d4537e',lt:'C',t:'llm'},\n  'deepseek':{x:55,y:84,l:'DeepSeek',c:'#3B6D11',lt:'D',t:'llm'},\n\n  'agent-conv':{x:68,y:15,l:'Agente de triaje',c:'#10b981',lt:'T',t:'ag'},\n  'agent-voz':{x:68,y:29,l:'Agente de voz',c:'#3b82f6',lt:'V',t:'ag'},\n  'agent-soporte':{x:68,y:43,l:'Agente de respuesta',c:'#f97316',lt:'R',t:'ag'},\n  'agent-fact':{x:68,y:58,l:'Agente de cumplimiento',c:'#eab308',lt:'C',t:'ag'},\n  'agent-anal':{x:68,y:73,l:'Agente de an\u00e1lisis',c:'#8b5cf6',lt:'A',t:'ag'},\n\n  'crm':{x:87,y:11,l:'SIEM',c:'#3b82f6',t:'cn',sub:'Splunk, Sentinel'},\n  'erp':{x:87,y:25,l:'EDR \/ Endpoints',c:'#3b82f6',t:'cn',sub:'CrowdStrike, Defender'},\n  'ticketing':{x:87,y:40,l:'Mesa de ayuda',c:'#3b82f6',t:'cn',sub:'Jira, ServiceNow'},\n  'fact-elec':{x:87,y:54,l:'Firewall \/ WAF',c:'#ef4444',t:'cn',sub:'Fortinet, Cloudflare'},\n  'google-ws':{x:87,y:68,l:'Identidad \/ IAM',c:'#3b82f6',t:'cn',sub:'Okta, Entra ID'},\n  'slack':{x:87,y:82,l:'Slack \/ Teams',c:'#3b82f6',t:'cn',sub:'Notificaciones'},\n\n  'postgresql':{x:13,y:95,l:'PostgreSQL',c:'#10b981',t:'dt'},\n  'mongodb':{x:27,y:95,l:'MongoDB',c:'#10b981',t:'dt'},\n  'redis':{x:41,y:95,l:'Redis',c:'#10b981',t:'dt'},\n  'archivos':{x:56,y:95,l:'Archivos',c:'#f97316',t:'dt'},\n  'storage':{x:71,y:95,l:'Almacenamiento',c:'#10b981',t:'dt'},\n  'audio':{x:87,y:95,l:'Audio',c:'#f97316',t:'dt'},\n};\n\nconst CS=[\n{id:'em-phish',ch:'email',t:'Triaje de phishing reportado',d:'Un empleado reenv\u00eda un correo sospechoso. Ruvic lo analiza, bloquea el dominio y contiene la campa\u00f1a.',kpi:'Triaje en menos de 30 segundos',\n path:['email','engine','memory','claude','agent-conv','fact-elec','agent-conv','engine','email'],\n steps:[\n  {n:'Correo electr\u00f3nico',dt:'El empleado reenv\u00eda: \"Este correo del banco se ve raro\"',c:'#EA4335',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como posible phishing, prioridad alta',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Correlaciona: 3 reportes similares en la \u00faltima hora',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'Analiza cabeceras, URLs y adjuntos del mensaje',c:'#d4537e',dir:'out'},\n  {n:'Agente de triaje',dt:'Confirma phishing: dominio suplantado registrado ayer',c:'#10b981',dir:'out'},\n  {n:'Firewall \/ WAF',dt:'Bloquea el dominio y purga el correo de 42 buzones',c:'#ef4444',dir:'ret'},\n  {n:'Agente de triaje',dt:'Documenta los IOCs y cierra el an\u00e1lisis',c:'#10b981',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Prepara la confirmaci\u00f3n y el aviso preventivo al equipo',c:'#534AB7',dir:'ret'},\n  {n:'Correo electr\u00f3nico',dt:'Responde: \"Amenaza contenida. Gracias por reportar \\uD83D\\uDEE1\"',c:'#EA4335',dir:'ret'},\n]},\n{id:'api-ransom',ch:'api',t:'Contenci\u00f3n de ransomware en endpoint',d:'El EDR reporta cifrado an\u00f3malo. Ruvic a\u00edsla el equipo y abre el incidente en segundos.',kpi:'Contenci\u00f3n en menos de 60 segundos',\n path:['api','engine','memory','deepseek','agent-soporte','erp','agent-soporte','engine','email'],\n steps:[\n  {n:'API (webhook)',dt:'EDR alerta: cifrado masivo de archivos en el host FIN-PC-041',c:'#4a5568',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como ransomware, severidad cr\u00edtica',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Host sin incidentes previos; usuario del \u00e1rea financiera',c:'#10b981',dir:'out'},\n  {n:'DeepSeek',dt:'Identifica el patr\u00f3n: familia LockBit, vector USB',c:'#3B6D11',dir:'out'},\n  {n:'Agente de respuesta',dt:'Ordena el aislamiento de red del endpoint',c:'#f97316',dir:'out'},\n  {n:'EDR \/ Endpoints',dt:'CrowdStrike a\u00edsla el host y termina el proceso malicioso',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de respuesta',dt:'Toma snapshot forense y abre el caso del incidente',c:'#f97316',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Prepara el reporte ejecutivo con la l\u00ednea de tiempo',c:'#534AB7',dir:'ret'},\n  {n:'Correo electr\u00f3nico',dt:'Notifica al CISO: \"Host aislado, cero propagaci\u00f3n\"',c:'#EA4335',dir:'ret'},\n]},\n{id:'vz-vish',ch:'voice',t:'Detecci\u00f3n de vishing en llamada',d:'Una llamada solicita un cambio de cuenta sensible. Ruvic verifica la identidad y detecta la suplantaci\u00f3n.',kpi:'Bloquea el fraude antes del da\u00f1o',\n path:['voice','engine','memory','gpt4o','agent-voz','google-ws','agent-voz','engine','voice'],\n steps:[\n  {n:'Voz \/ SIP',dt:'Llamada entrante: \"Necesito cambiar la cuenta de n\u00f3mina del gerente\"',c:'#378ADD',dir:'out'},\n  {n:'Ruvic Engine',dt:'Transcribe en tiempo real y detecta solicitud sensible',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'El n\u00famero no coincide con el registrado del gerente',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Analiza se\u00f1ales: urgencia, presi\u00f3n, datos incompletos',c:'#10a37f',dir:'out'},\n  {n:'Agente de voz',dt:'Inicia verificaci\u00f3n de identidad reforzada',c:'#3b82f6',dir:'out'},\n  {n:'Identidad \/ IAM',dt:'Okta: reto MFA fallido, identidad no verificada',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de voz',dt:'Marca la llamada como intento de vishing',c:'#3b82f6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Registra el incidente y alerta al equipo de seguridad',c:'#534AB7',dir:'ret'},\n  {n:'Voz \/ SIP',dt:'Finaliza: \"No es posible continuar con esta solicitud\"',c:'#378ADD',dir:'ret'},\n]},\n{id:'wa-mfa',ch:'whatsapp',t:'Restablecimiento seguro de credenciales',d:'Un empleado pide restablecer su contrase\u00f1a. Ruvic verifica identidad con MFA y ejecuta el cambio.',kpi:'Cero tickets por contrase\u00f1as',\n path:['whatsapp','engine','memory','gemini','agent-soporte','google-ws','agent-soporte','engine','whatsapp'],\n steps:[\n  {n:'WhatsApp',dt:'El empleado escribe: \"Olvid\u00e9 mi contrase\u00f1a y tengo reuni\u00f3n en 10 min\"',c:'#25D366',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica: restablecimiento de credenciales',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Valida usuario, dispositivo y horario habituales',c:'#10b981',dir:'out'},\n  {n:'Gemini',dt:'Eval\u00faa el riesgo de la solicitud: bajo',c:'#4285F4',dir:'out'},\n  {n:'Agente de respuesta',dt:'Dispara el reto MFA al dispositivo registrado',c:'#f97316',dir:'out'},\n  {n:'Identidad \/ IAM',dt:'Entra ID confirma el MFA y restablece la credencial',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de respuesta',dt:'Genera un enlace temporal de un solo uso',c:'#f97316',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Registra la operaci\u00f3n en la bit\u00e1cora de auditor\u00eda',c:'#534AB7',dir:'ret'},\n  {n:'WhatsApp',dt:'Env\u00eda: \"Listo, enlace v\u00e1lido por 10 minutos \\uD83D\\uDD10\"',c:'#25D366',dir:'ret'},\n]},\n{id:'tg-ioc',ch:'telegram',t:'Enriquecimiento de IOCs para el SOC',d:'Un analista env\u00eda un hash sospechoso. Ruvic lo enriquece con inteligencia de amenazas al instante.',kpi:'Ahorra 25 min por investigaci\u00f3n',\n path:['telegram','engine','memory','gpt4o','agent-anal','crm','agent-anal','engine','telegram'],\n steps:[\n  {n:'Telegram',dt:'El analista env\u00eda: \"Revisa este hash: a3f9\u2026\"',c:'#0088cc',dir:'out'},\n  {n:'Ruvic Engine',dt:'Detecta IOC tipo SHA-256, inicia el enriquecimiento',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Sin coincidencias en investigaciones previas',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Estructura la consulta de threat intelligence',c:'#10a37f',dir:'out'},\n  {n:'Agente de an\u00e1lisis',dt:'Cruza el hash contra las fuentes de inteligencia',c:'#8b5cf6',dir:'out'},\n  {n:'SIEM',dt:'Splunk: 2 endpoints ejecutaron el binario ayer',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de an\u00e1lisis',dt:'Veredicto: malware confirmado, alcance de 2 hosts',c:'#8b5cf6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Genera el resumen con TTPs y recomendaciones',c:'#534AB7',dir:'ret'},\n  {n:'Telegram',dt:'Responde: \"Malicioso \u2714 \u00b7 2 hosts afectados \u00b7 ver informe\"',c:'#0088cc',dir:'ret'},\n]},\n{id:'api-vuln',ch:'api',t:'Priorizaci\u00f3n de vulnerabilidades',d:'El esc\u00e1ner publica nuevos hallazgos. Ruvic los prioriza por riesgo real y crea los tickets.',kpi:'Reduce el backlog de parcheo un 70%',\n path:['api','engine','memory','claude','agent-anal','ticketing','agent-anal','engine','api'],\n steps:[\n  {n:'API directa',dt:'El esc\u00e1ner publica 214 hallazgos del ciclo nocturno',c:'#4a5568',dir:'out'},\n  {n:'Ruvic Engine',dt:'Ingesta y deduplica: 38 vulnerabilidades \u00fanicas',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Cruza con el inventario: 5 afectan sistemas expuestos',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'Prioriza por explotabilidad real (EPSS) y contexto',c:'#d4537e',dir:'out'},\n  {n:'Agente de an\u00e1lisis',dt:'Arma el plan: 3 cr\u00edticas para parcheo inmediato',c:'#8b5cf6',dir:'out'},\n  {n:'Mesa de ayuda',dt:'Jira crea 3 tickets con SLA de 24 horas',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de an\u00e1lisis',dt:'Asigna responsables y adjunta la gu\u00eda de remediaci\u00f3n',c:'#8b5cf6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Actualiza el tablero de riesgo de la organizaci\u00f3n',c:'#534AB7',dir:'ret'},\n  {n:'API directa',dt:'Retorna: {cr\u00edticas: 3, SLA: 24h, riesgo: -12%}',c:'#4a5568',dir:'ret'},\n]},\n{id:'wg-access',ch:'widget',t:'Gesti\u00f3n de accesos con aprobaci\u00f3n',d:'Un empleado solicita acceso a una app desde el portal. Ruvic valida la pol\u00edtica y lo aprovisiona.',kpi:'Accesos otorgados 10x m\u00e1s r\u00e1pido',\n path:['widget','engine','memory','claude','agent-fact','google-ws','agent-fact','engine','widget'],\n steps:[\n  {n:'Widget web',dt:'Solicitud: \"Necesito acceso a Tableau para el cierre de mes\"',c:'#7c3aed',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica: solicitud de acceso a aplicaci\u00f3n financiera',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Rol del usuario: analista financiero, \u00e1rea correcta',c:'#10b981',dir:'out'},\n  {n:'Claude',dt:'Eval\u00faa la pol\u00edtica: acceso permitido con caducidad',c:'#d4537e',dir:'out'},\n  {n:'Agente de cumplimiento',dt:'Solicita la aprobaci\u00f3n al due\u00f1o de la aplicaci\u00f3n',c:'#eab308',dir:'out'},\n  {n:'Identidad \/ IAM',dt:'Okta aprovisiona el acceso con vigencia de 90 d\u00edas',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de cumplimiento',dt:'Registra la evidencia para la auditor\u00eda',c:'#eab308',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Cierra la solicitud y programa la revocaci\u00f3n autom\u00e1tica',c:'#534AB7',dir:'ret'},\n  {n:'Widget web',dt:'Notifica: \"Acceso activo \u00b7 expira el 9 de octubre\"',c:'#7c3aed',dir:'ret'},\n]},\n{id:'em-dlp',ch:'email',t:'Prevenci\u00f3n de fuga de datos (DLP)',d:'Un correo saliente incluye datos de tarjetas. Ruvic lo retiene y gu\u00eda al usuario.',kpi:'Reduce fugas de datos un 85%',\n path:['email','engine','memory','gemini','agent-fact','fact-elec','agent-fact','engine','email'],\n steps:[\n  {n:'Correo electr\u00f3nico',dt:'Correo saliente con el adjunto \"clientes_q3.xlsx\"',c:'#EA4335',dir:'out'},\n  {n:'Ruvic Engine',dt:'El escaneo DLP detecta 1.200 n\u00fameros de tarjeta',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'El usuario no tiene una excepci\u00f3n de pol\u00edtica activa',c:'#10b981',dir:'out'},\n  {n:'Gemini',dt:'Clasifica la sensibilidad: datos PCI, nivel cr\u00edtico',c:'#4285F4',dir:'out'},\n  {n:'Agente de cumplimiento',dt:'Retiene el env\u00edo y aplica la pol\u00edtica PCI-DSS',c:'#eab308',dir:'out'},\n  {n:'Firewall \/ WAF',dt:'Bloquea la salida y pone el archivo en cuarentena cifrada',c:'#ef4444',dir:'ret'},\n  {n:'Agente de cumplimiento',dt:'Notifica al oficial de datos con la evidencia',c:'#eab308',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Prepara la gu\u00eda de env\u00edo seguro para el usuario',c:'#534AB7',dir:'ret'},\n  {n:'Correo electr\u00f3nico',dt:'Responde: \"Env\u00edo retenido: usa el canal cifrado \\uD83D\\uDD12\"',c:'#EA4335',dir:'ret'},\n]},\n{id:'wa-inc',ch:'whatsapp',t:'Reporte de dispositivo perdido',d:'Un empleado reporta su laptop perdida. Ruvic revoca sesiones y activa el borrado remoto.',kpi:'Superficie de riesgo cerrada al instante',\n path:['whatsapp','engine','memory','gpt4o','agent-soporte','erp','agent-soporte','engine','whatsapp'],\n steps:[\n  {n:'WhatsApp',dt:'El empleado escribe: \"Perd\u00ed mi laptop en el aeropuerto\"',c:'#25D366',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica: p\u00e9rdida de activo con riesgo de datos',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Identifica el equipo: DELL-7420, cifrado de disco activo',c:'#10b981',dir:'out'},\n  {n:'GPT-4o',dt:'Prioriza acciones seg\u00fan el perfil de acceso del usuario',c:'#10a37f',dir:'out'},\n  {n:'Agente de respuesta',dt:'Revoca las sesiones y tokens activos del usuario',c:'#f97316',dir:'out'},\n  {n:'EDR \/ Endpoints',dt:'Defender bloquea el equipo y activa el borrado remoto',c:'#3b82f6',dir:'ret'},\n  {n:'Agente de respuesta',dt:'Abre el caso y solicita el equipo de reemplazo',c:'#f97316',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Documenta la l\u00ednea de tiempo del incidente',c:'#534AB7',dir:'ret'},\n  {n:'WhatsApp',dt:'Confirma: \"Equipo bloqueado. Tu cuenta est\u00e1 segura \u2714\"',c:'#25D366',dir:'ret'},\n]},\n{id:'tg-sec',ch:'telegram',t:'Bloqueo de fuerza bruta en tiempo real',d:'Ruvic detecta una anomal\u00eda en los logs, la analiza y alerta al equipo v\u00eda Telegram.',kpi:'Reduce incidentes de seguridad un 50%',\n path:['api','engine','memory','deepseek','agent-anal','postgresql','agent-anal','engine','telegram'],\n steps:[\n  {n:'API (webhook)',dt:'Alerta autom\u00e1tica: m\u00e1s de 50 intentos de inicio de sesi\u00f3n fallidos',c:'#4a5568',dir:'out'},\n  {n:'Ruvic Engine',dt:'Clasifica como incidente de seguridad, prioridad alta',c:'#534AB7',dir:'out'},\n  {n:'Memoria',dt:'Correlaciona con incidentes previos de la misma IP',c:'#10b981',dir:'out'},\n  {n:'DeepSeek',dt:'Analiza el patr\u00f3n: fuerza bruta desde la IP 45.33.x.x',c:'#3B6D11',dir:'out'},\n  {n:'Agente de an\u00e1lisis',dt:'Consulta logs detallados y geolocaliza la IP',c:'#8b5cf6',dir:'out'},\n  {n:'PostgreSQL',dt:'Retorna: 847 intentos en 10 minutos, origen desconocido',c:'#10b981',dir:'ret'},\n  {n:'Agente de an\u00e1lisis',dt:'Genera el reporte del incidente con recomendaciones',c:'#8b5cf6',dir:'ret'},\n  {n:'Ruvic Engine',dt:'Bloquea la IP autom\u00e1ticamente y prepara la alerta',c:'#534AB7',dir:'ret'},\n  {n:'Telegram',dt:'Alerta al equipo: \"\\uD83D\\uDEA8 IP bloqueada, ver reporte adjunto\"',c:'#0088cc',dir:'ret'},\n]}\n];\n\nconst CHANNELS=[\n  {id:'all',l:'Todos',c:'#6b7280'},\n  {id:'whatsapp',l:'WhatsApp',c:'#25D366'},\n  {id:'telegram',l:'Telegram',c:'#0088cc'},\n  {id:'email',l:'Correo',c:'#EA4335'},\n  {id:'voice',l:'Voz',c:'#378ADD'},\n  {id:'api',l:'API',c:'#4a5568'},\n  {id:'widget',l:'Widget',c:'#7c3aed'},\n];\n\n\/* ---------------- ESTADO ---------------- *\/\nlet ac=null,anim=false,cs=0,dots=[],hl=new Set(),W,H,cvs,ctx,filt='all',spd=3,advTmr=null,isNarrow=false;\nconst $=id=>root.querySelector('#'+id);\nconst widget=$('rbs-widget'),ca=$('rbs-ca'),zp=$('rbs-zp');\n\nfunction lineIdle(){return root.dataset.theme==='light'?'rgba(34,38,71,0.14)':'rgba(250,240,228,0.12)';}\n\n\/* ---------------- INIT ---------------- *\/\nfunction init(){\n  cvs=$('rbs-fc');ctx=cvs.getContext('2d');\n  renderFilters();renderCases();\n  \/\/ Doble rAF: garantiza que el browser ya calcul\u00f3 dimensiones reales (importante en WP)\n  requestAnimationFrame(()=>requestAnimationFrame(applyLayout));\n  window.addEventListener('load',applyLayout);\n  \/\/ listeners\n  $('rbs-pb').addEventListener('click',play);\n  $('rbs-rst').addEventListener('click',reset);\n  $('rbs-spd').addEventListener('input',updSpd);\n  $('rbs-theme').addEventListener('click',toggleTheme);\n  ca.addEventListener('click',e=>{ if(!didPan ? (e.target===cvs ? true : e.target===ca ? true : e.target===zp) : false) reset(); });\n  \/\/ tema guardado\n  try{const sv=localStorage.getItem('ruvicThemeSec');if(sv)root.dataset.theme=sv;}catch(e){}\n  \/\/ decidir layout: load + resize + orientationchange (+ ResizeObserver si est\u00e1 disponible)\n  let rt;\n  window.addEventListener('resize',()=>{clearTimeout(rt);rt=setTimeout(applyLayout,120);});\n  window.addEventListener('orientationchange',()=>setTimeout(applyLayout,250));\n  if(window.ResizeObserver){let raf;new ResizeObserver(()=>{cancelAnimationFrame(raf);raf=requestAnimationFrame(applyLayout);}).observe(widget);}\n  setupTouch();\n  requestAnimationFrame(dr);\n}\n\nfunction toggleTheme(){\n  const next=root.dataset.theme==='light'?'dark':'light';\n  root.dataset.theme=next;\n  try{localStorage.setItem('ruvicThemeSec',next);}catch(e){}\n}\n\n\/* ---------------- LAYOUT (desktop vs m\u00f3vil) ---------------- *\/\nfunction applyLayout(){\n  isNarrow=widget.clientWidth<760;\n  root.classList.toggle('is-narrow',isNarrow);\n  root.classList.toggle('is-xnarrow',widget.clientWidth<440);\n  rsz();renderNodes();\n  if(isNarrow){recalcZoom();}else{resetTransform();}\n}\n\nfunction rsz(){\n  const dp=window.devicePixelRatio ? window.devicePixelRatio : 1;\n  if(isNarrow){W=1400;H=900;}\n  else{W=ca.clientWidth;H=ca.clientHeight;}\n  cvs.width=W*dp;cvs.height=H*dp;\n  cvs.style.width=W+'px';cvs.style.height=H+'px';\n  const nl=$('rbs-nl');\n  nl.style.width=W+'px';nl.style.height=H+'px';\n  zp.style.width=W+'px';zp.style.height=H+'px';\n  ctx.setTransform(dp,0,0,dp,0,0);\n}\n\nfunction p(id){const n=N[id];return{x:n.x\/100*W,y:n.y\/100*H};}\n\n\/* ---------------- RENDER: filtros \/ casos ---------------- *\/\nfunction renderFilters(){\n  $('rbs-filters').innerHTML=CHANNELS.map(c=>\n    `<button class=\"fb${filt===c.id?' act':''}\" data-f=\"${c.id}\" type=\"button\"\n       style=\"${filt===c.id?'background:'+c.c+';color:#fff;border-color:'+c.c:''}\">${c.l}<\/button>`).join('');\n  $('rbs-filters').querySelectorAll('.fb').forEach(b=>b.addEventListener('click',()=>setFilt(b.dataset.f)));\n}\nfunction setFilt(f){\n  filt=f;renderFilters();\n  if(f==='all'){renderCases();return;}\n  const m=CS.filter(c=>c.ch===f);if(m.length)sel(CS.indexOf(m[0]));else renderCases();\n}\n\nfunction renderCases(){\n  const el=$('rbs-cl');\n  const filtered=filt==='all'?CS:CS.filter(c=>c.ch===filt);\n  if(!filtered.length){el.innerHTML='<p class=\"rb-empty\" style=\"padding:18px;text-align:center\">No hay casos para este canal<\/p>';return;}\n  el.innerHTML=filtered.map(c=>{\n    const ri=CS.indexOf(c);const ch=N[c.path[0]];\n    return`<button class=\"cb${(ac ? ac.id===c.id : false) ? ' act' : ''}\" data-i=\"${ri}\" type=\"button\" style=\"--cbc:${ch.c}\">\n      <div class=\"cb-ch\"><span class=\"d\" style=\"background:${ch.c}\"><\/span>${ch.l}<\/div>\n      <div class=\"cb-t\">${c.t}<\/div>\n      <div class=\"cb-desc\">${c.d}<\/div>\n      <div class=\"cb-kpi\">\u25b2 ${c.kpi}<\/div>\n    <\/button>`;}).join('');\n  el.querySelectorAll('.cb').forEach(b=>b.addEventListener('click',()=>sel(+b.dataset.i)));\n}\n\n\/* ---------------- RENDER: nodos ---------------- *\/\nfunction renderNodes(){\n  const ly=$('rbs-nl');ly.innerHTML='';\n  const labels=[\n    {t:'Canales',x:13,y:1.5},{t:'Ruvic Engine',x:41,y:1.5},\n    {t:'Orquestaci\u00f3n',x:68,y:1.5},{t:'Conectores',x:88,y:1.5},\n    {t:'Datos \u00b7 Archivos \u00b7 Almacenamiento',x:50,y:89}\n  ];\n  labels.forEach(l=>{\n    const e=document.createElement('div');e.className='sl';\n    e.style.cssText=`left:${l.x}%;top:${l.y}%;transform:translateX(-50%)`;e.textContent=l.t;ly.appendChild(e);\n  });\n\n  Object.entries(N).forEach(([id,n])=>{\n    const e=document.createElement('div');\n    const dim=(hl.size>0 ? !hl.has(id) : false) ? ' dim' : '';\n    const hlc=hl.has(id)?' hl':'';\n    const clk=n.t==='ch'?' clk':'';\n    e.className='nd'+dim+hlc+clk;e.id='rbs-nd-'+id;\n    let gc='';\n    if(hl.has(id)){\n      if(n.t==='ch')gc='gt';else if(n.t==='core' ? true : n.t==='sub' ? true : n.t==='llm')gc='gp';\n      else if(n.t==='ag')gc='go';else if(n.t==='cn')gc=n.c==='#ef4444'?'gr':'gb';else gc='gb';\n    }\n    e.style.cssText=`left:${n.x}%;top:${n.y}%;transform:translate(-50%,-50%)`;\n    \/\/ Icono como <canvas>: caja de color + letra se DIBUJAN como p\u00edxeles.\n    \/\/ Los p\u00edxeles de un canvas son 100% inmunes al CSS de Kadence Y a cualquier\n    \/\/ plugin de WordPress (lazy-load, optimizador de im\u00e1genes, sanitizador, CSP).\n    \/\/ Es la \u00fanica t\u00e9cnica que no puede fallar por configuraci\u00f3n externa.\n    function svgIc(icId,color,letter,w,h,rx,fs,cls){\n      return `<canvas id=\"rbs-ic-${icId}\" class=\"${cls}\" data-w=\"${w}\" data-h=\"${h}\" data-rx=\"${rx}\" data-fs=\"${fs}\" data-color=\"${color}\" data-letter=\"${letter}\"><\/canvas>`;\n    }\n    if(n.t==='core'){\n      e.innerHTML=`<div class=\"nc nc-core ${gc}\">${svgIc(id,n.c,n.lt,48,48,12,20,'ic ic-lg')}<div class=\"nt nt-lg\">${n.l}<\/div><div class=\"ns\">Orquestaci\u00f3n multi-agente<\/div><div style=\"display:flex;gap:5px;margin-top:8px;flex-wrap:wrap;justify-content:center\"><span class=\"tg\" style=\"background:rgba(139,128,255,.22);color:#a59cff\">Clasificador<\/span><span class=\"tg\" style=\"background:rgba(139,128,255,.22);color:#a59cff\">Enrutador LLM<\/span><span class=\"tg\" style=\"background:rgba(16,185,129,.22);color:#34d399\">Contexto<\/span><\/div><\/div>`;\n    }else if(n.t==='ch'){\n      e.addEventListener('click',()=>filterCh(id));\n      e.innerHTML=`<div class=\"nc ${gc}\">${svgIc(id,n.c,n.lt,36,36,18,13,'ic')}<div class=\"nt\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='ag'){\n      e.innerHTML=`<div class=\"nc ${gc}\">${svgIc(id,n.c,n.lt,36,36,18,13,'ic')}<div class=\"nt\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='sub' ? true : n.t==='llm'){\n      e.innerHTML=`<div class=\"ng ${gc}\" style=\"text-align:center\">${svgIc(id,n.c,n.lt,30,30,8,14,'ic-sm')}<div class=\"nt\" style=\"font-size:10.5px;margin-top:5px\">${n.l}<\/div><\/div>`;\n    }else if(n.t==='cn'){\n      e.innerHTML=`<div class=\"nc ${gc}\" style=\"min-width:128px\"><div class=\"nt\">${n.l}<\/div>${n.sub?'<div class=\"ns\">'+n.sub+'<\/div>':''}<\/div>`;\n    }else{\n      e.innerHTML=`<div class=\"ng ${gc}\" style=\"min-width:auto;white-space:nowrap\"><div class=\"nt\" style=\"font-size:11px\">${n.l}<\/div><\/div>`;\n    }\n    ly.appendChild(e);\n  });\n  \/\/ Dibuja cada icono en su canvas (caja + letra como p\u00edxeles, inmune a CSS\/plugins)\n  ly.querySelectorAll('canvas[data-letter]').forEach(drawIc);\n}\n\n\/* Dibuja un icono (rect redondeado + letra blanca) en un <canvas> *\/\nfunction drawIc(cv){\n  const w=+cv.dataset.w,h=+cv.dataset.h,rx=Math.min(+cv.dataset.rx,w\/2,h\/2),fs=+cv.dataset.fs;\n  const color=cv.dataset.color,letter=cv.dataset.letter;\n  const dpr=window.devicePixelRatio||1;\n  cv.width=Math.round(w*dpr);cv.height=Math.round(h*dpr);\n  cv.style.width=w+'px';cv.style.height=h+'px';\n  const x=cv.getContext('2d');\n  x.scale(dpr,dpr);\n  x.clearRect(0,0,w,h);\n  \/\/ rect redondeado\n  x.beginPath();\n  x.moveTo(rx,0);\n  x.arcTo(w,0,w,h,rx);\n  x.arcTo(w,h,0,h,rx);\n  x.arcTo(0,h,0,0,rx);\n  x.arcTo(0,0,w,0,rx);\n  x.closePath();\n  x.fillStyle=color;x.fill();\n  \/\/ letra blanca centrada\n  x.fillStyle='#ffffff';\n  x.font='800 '+fs+'px system-ui,-apple-system,\"Segoe UI\",sans-serif';\n  x.textAlign='center';x.textBaseline='middle';\n  x.fillText(letter,w\/2,h\/2+0.5);\n}\n\n\/* ---------------- RENDER: tracker ---------------- *\/\nfunction renderSteps(c){\n  const t=$('rbs-trk');\n  t.innerHTML=`<h4>Flujo activo <span>0 \/ ${c.steps.length}<\/span><\/h4>`+\n    c.steps.map((s,i)=>`<div class=\"stp\" id=\"rbs-s-${i}\"><div class=\"stp-n\" id=\"rbs-sn-${i}\" style=\"background:${s.c}\">${i+1}<\/div><div class=\"stp-i\"><div class=\"stp-nm\">${s.dir==='ret'?'\u2190 ':'\u2192 '}${s.n}<\/div><div class=\"stp-dt\">${s.dt}<\/div><\/div><\/div>`).join('');\n}\n\n\/* ---------------- INTERACCI\u00d3N ---------------- *\/\nfunction sel(i){\n  if(advTmr){clearTimeout(advTmr);advTmr=null;}\n  ac=CS[i];cs=0;dots=[];anim=false;\n  hl=new Set(ac.path);renderNodes();renderSteps(ac);renderCases();\n  $('rbs-pb').disabled=false;\n}\nfunction filterCh(id){\n  filt=id;renderFilters();renderCases();\n  const m=CS.filter(c=>c.ch===id);if(m.length)sel(CS.indexOf(m[0]));\n}\nfunction updSpd(){spd=+$('rbs-spd').value;$('rbs-spdV').textContent=spd+'x';}\n\nfunction play(){\n  if(!ac ? true : anim)return;anim=true;cs=0;dots=[];\n  $('rbs-pb').disabled=true;advance();\n}\nfunction advance(){\n  if(!ac ? true : cs>=ac.path.length-1){anim=false;$('rbs-pb').disabled=false;return;}\n  const se=$('rbs-s-'+cs);\n  if(se){\n    se.classList.add('on');\n    const trk=$('rbs-trk');\n    trk.scrollTo({top:Math.max(0,se.offsetTop-trk.offsetTop-18),behavior:'smooth'});\n  }\n  for(let i=0;i<cs;i++){const pe=$('rbs-s-'+i);if(pe){pe.classList.remove('on');pe.classList.add('dn');}}\n  const h4=$('rbs-trk').querySelector('h4 span');if(h4)h4.textContent=(cs+1)+' \/ '+ac.steps.length;\n  const icEl=$('rbs-ic-'+ac.path[cs]);\n  if(icEl){icEl.classList.remove('pulse');void icEl.offsetWidth;icEl.classList.add('pulse');}\n  const snEl=$('rbs-sn-'+cs);\n  if(snEl){snEl.classList.remove('pulse');void snEl.offsetWidth;snEl.classList.add('pulse');}\n\n  const p1=p(ac.path[cs]),p2=p(ac.path[cs+1]);\n  const dir=ac.steps[cs]?ac.steps[cs].dir:'out';\n  const col=dir==='ret'?'#3b82f6':(ac.steps[cs]?ac.steps[cs].c:'#534AB7');\n  dots.push({x1:p1.x,y1:p1.y,x2:p2.x,y2:p2.y,t:0,sp:0.012*spd,c:col,a:true});\n  cs++;\n  advTmr=setTimeout(advance,Math.max(300,800\/spd));\n}\nfunction reset(){\n  if(advTmr){clearTimeout(advTmr);advTmr=null;}\n  ac=null;anim=false;cs=0;dots=[];hl.clear();filt='all';\n  renderFilters();renderCases();renderNodes();\n  $('rbs-pb').disabled=true;\n  $('rbs-trk').innerHTML='<h4>Flujo activo<\/h4><p class=\"rb-empty\">Selecciona un caso de uso para visualizar cada paso.<\/p>';\n}\n\n\/* ---------------- CANVAS LOOP ---------------- *\/\nfunction dr(){\n  ctx.clearRect(0,0,W,H);\n  if(!ac)drawIdle();else drawActive();\n  dots.forEach(d=>{\n    if(!d.a)return;d.t+=d.sp;if(d.t>=1){d.a=false;return;}\n    const t=d.t,mx=(d.x1+d.x2)\/2,my=(d.y1+d.y2)\/2;\n    const x=(1-t)**2*d.x1+2*(1-t)*t*mx+t**2*d.x2;\n    const y=(1-t)**2*d.y1+2*(1-t)*t*my+t**2*d.y2;\n    ctx.beginPath();ctx.arc(x,y,18,0,Math.PI*2);ctx.fillStyle=hr(d.c,.09);ctx.fill();\n    ctx.beginPath();ctx.arc(x,y,10,0,Math.PI*2);ctx.fillStyle=hr(d.c,.28);ctx.fill();\n    ctx.beginPath();ctx.arc(x,y,5,0,Math.PI*2);ctx.fillStyle=d.c;ctx.fill();\n  });\n  dots=dots.filter(d=>d.a);\n  requestAnimationFrame(dr);\n}\nfunction drawIdle(){\n  const col=lineIdle();\n  \/\/ Canales \u2192 Engine\n  ['whatsapp','telegram','email','voice','api','widget'].forEach(c=>{const a=p(c),b=p('engine');bz(a.x+50,a.y,b.x-90,b.y,col,1.4);});\n  \/\/ Engine \u2192 Agentes\n  ['agent-conv','agent-voz','agent-soporte','agent-fact','agent-anal'].forEach(a=>{const s=p('engine'),e=p(a);bz(s.x+90,s.y,e.x-60,e.y,col,1.4);});\n}\nfunction drawActive(){\n  for(let i=0;i<ac.path.length-1;i++){\n    const a=p(ac.path[i]),b=p(ac.path[i+1]);\n    const done=i<cs,dir=ac.steps[i]?ac.steps[i].dir:'out';\n    const col=dir==='ret'?'#3b82f6':(ac.steps[i]?ac.steps[i].c:'#534AB7');\n    bz(a.x,a.y,b.x,b.y,hr(col,done?.32:.07),done?2.6:1.2);\n  }\n}\nfunction bz(x1,y1,x2,y2,c,w){\n  ctx.beginPath();ctx.moveTo(x1,y1);\n  const mx=(x1+x2)\/2,my=(y1+y2)\/2;\n  ctx.quadraticCurveTo(mx,my,x2,y2);\n  ctx.strokeStyle=c;ctx.lineWidth=w;ctx.stroke();\n}\nfunction hr(h,a){const r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16);return`rgba(${r},${g},${b},${a})`;}\n\n\/* ---------------- ZOOM \/ PAN T\u00c1CTIL (m\u00f3vil) ---------------- *\/\nlet scale=1,tx=0,ty=0,lastDist=0,isPinching=false,isDragging=false,startTx=0,startTy=0,didPan=false;\nfunction applyTransform(){zp.style.transform=`translate(${tx}px,${ty}px) scale(${scale})`;}\nfunction resetTransform(){scale=1;tx=0;ty=0;zp.style.transform='none';}\nfunction recalcZoom(){\n  const cw=ca.clientWidth,ch=ca.clientHeight;\n  scale=Math.min(cw\/1400,ch\/900);\n  tx=(cw-1400*scale)\/2;ty=(ch-900*scale)\/2;\n  applyTransform();\n}\nfunction setupTouch(){\n  if(!('ontouchstart' in window))return;\n  ca.addEventListener('touchstart',e=>{\n    if(!isNarrow)return;\n    if(e.touches.length===2){isPinching=true;isDragging=false;\n      const dx=e.touches[0].clientX-e.touches[1].clientX,dy=e.touches[0].clientY-e.touches[1].clientY;\n      lastDist=Math.hypot(dx,dy);\n    }else if(e.touches.length===1){isDragging=true;didPan=false;\n      startTx=e.touches[0].clientX-tx;startTy=e.touches[0].clientY-ty;}\n  },{passive:true});\n  ca.addEventListener('touchmove',e=>{\n    if(!isNarrow)return;\n    if(e.touches.length===2 ? isPinching : false){e.preventDefault();\n      const dx=e.touches[0].clientX-e.touches[1].clientX,dy=e.touches[0].clientY-e.touches[1].clientY;\n      const dist=Math.hypot(dx,dy),ratio=dist\/lastDist;\n      const ns=Math.min(4,Math.max(0.2,scale*ratio));\n      const rect=ca.getBoundingClientRect();\n      const mx=(e.touches[0].clientX+e.touches[1].clientX)\/2-rect.left;\n      const my=(e.touches[0].clientY+e.touches[1].clientY)\/2-rect.top;\n      tx=mx-(mx-tx)*ns\/scale;ty=my-(my-ty)*ns\/scale;scale=ns;lastDist=dist;applyTransform();\n    }else if(e.touches.length===1 ? isDragging : false){e.preventDefault();didPan=true;\n      tx=e.touches[0].clientX-startTx;ty=e.touches[0].clientY-startTy;applyTransform();}\n  },{passive:false});\n  ca.addEventListener('touchend',e=>{\n    if(e.touches.length<2)isPinching=false;\n    if(e.touches.length===0){isDragging=false;setTimeout(()=>{didPan=false;},50);}\n  },{passive:true});\n}\n\ninit();\n\n\/* Animacion de entrada: revela la seccion al entrar en viewport *\/\n(function(){\n  root.classList.add('rv-anim');\n  function inview(){root.classList.add('rv-in');}\n  if('IntersectionObserver' in window){\n    var io=new IntersectionObserver(function(es){\n      for(var i=0;i<es.length;i++){ if(es[i].isIntersecting){ inview(); io.disconnect(); } }\n    },{threshold:.15});\n    io.observe(root);\n  } else { inview(); }\n  setTimeout(inview,3000); \/* respaldo: nada queda oculto *\/\n})();\n\n\/\/ Forzar estilos del slider que Kadence sobreescribe (solo lo independiente del tema:\n\/\/ borde\/sombra\/padding). El COLOR de fondo lo maneja el CSS por tema para que cambie\n\/\/ correctamente al alternar claro\/oscuro.\n(function(){\n  const rng=root.querySelector('#rbs-spd');\n  if(!rng)return;\n  rng.style.setProperty('border','none','important');\n  rng.style.setProperty('box-shadow','none','important');\n  rng.style.setProperty('padding','0','important');\n  rng.style.setProperty('outline','none','important');\n})();\n\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Demo en vivo \u00b7 Voz IA No te lo contamos: h\u00e1blalo con Ruvic. Presiona el bot\u00f3n y conversa en tiempo real con un agente de voz IA. Sin formularios, sin esperas: una llamada directa desde tu navegador. \u2713Conversaci\u00f3n natural con latencia de milisegundos \u2713Entiende la intenci\u00f3n sin men\u00fas ni extensiones \u2713Disponible 24\/7, igual que en&#8230;<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"hide","_kad_post_layout":"fullwidth","_kad_post_sidebar_id":"","_kad_post_content_style":"unboxed","_kad_post_vertical_padding":"hide","_kad_post_feature":"hide","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"<!-- ================================================   BLOQUE 00 \u00b7 TOKENS GLOBALES   \u25ba Pegar UNA SOLA VEZ en WordPress:     Apariencia \u2192 Personalizar \u2192 CSS adicional     O en el primer bloque \"HTML personalizado\" de la p\u00e1gina.   \u25ba Fuentes: a\u00f1adir en el <head> del tema (functions.php o plugin):     <link href=\"https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&family=Syne:wght@500;600;700;800&display=swap\" rel=\"stylesheet\" \/> ================================================ -->  <style> \/* \u2500\u2500 TOKENS GLOBALES ROBIN AI \u00b7 MOTOR DE IA \u2500\u2500 *\/ :root {   --rvp-navy:        #0F1B3C;   --rvp-navy-deep:   #0A1230;   --rvp-navy-soft:   #18234A;   --rvp-navy-card:   #1A2649;   --rvp-navy-line:   rgba(255,255,255,0.08);    --rvp-red:         #E8344B;   --rvp-red-deep:    #C42339;   --rvp-red-soft:    #F76A7B;   --rvp-mustard:     #E8B53C;   --rvp-coral:       #F4A78C;    --rvp-white:       #FFFFFF;   --rvp-cream:       #FDF2E1;   --rvp-cream-border:#F0E6D3;    --rvp-text:        #F5F5F8;   --rvp-text-muted:  rgba(245,245,248,0.68);   --rvp-text-subtle: rgba(245,245,248,0.42);   --rvp-text-dark:   #0F1B3C;   --rvp-text-gray:   #6B7280;    --rvp-r-sm:   8px;   --rvp-r-md:   14px;   --rvp-r-lg:   22px;   --rvp-r-pill: 999px;    --rvp-sp3:  12px;   --rvp-sp4:  16px;   --rvp-sp5:  24px;   --rvp-sp6:  32px;   --rvp-sp7:  48px;   --rvp-sp8:  64px;   --rvp-sp9:  96px;   --rvp-sp10: 128px;    --rvp-font-display: 'Syne', sans-serif;   --rvp-font-body:    'DM Sans', sans-serif;   --rvp-font-mono:    'JetBrains Mono', monospace;    --rvp-ease: cubic-bezier(0.22,1,0.36,1);   --rvp-container: 1240px; }  \/* \u2500\u2500 RESET SCOPED (no afecta el tema WP) \u2500\u2500 *\/ .rvp-wrap *, .rvp-wrap *::before, .rvp-wrap *::after { box-sizing: border-box; } .rvp-wrap { -webkit-font-smoothing: antialiased; } .rvp-wrap img, .rvp-wrap svg { display: block; max-width: 100%; } .rvp-wrap a { color: inherit; text-decoration: none; } .rvp-wrap ul { list-style: none; padding: 0; margin: 0; }  \/* \u2500\u2500 CONTENEDOR \u2500\u2500 *\/ .rvp-inner {   width: 100%;   max-width: var(--rvp-container);   margin: 0 auto;   padding: 0 var(--rvp-sp5); }  \/* \u2500\u2500 EYEBROW \u2500\u2500 *\/ .rvp-eyebrow {   display: inline-flex;   align-items: center;   gap: var(--rvp-sp3);   font-family: var(--rvp-font-body);   font-size: 11px;   font-weight: 500;   letter-spacing: 0.16em;   text-transform: uppercase;   color: var(--rvp-red);   margin-bottom: 16px; } .rvp-eyebrow::before {   content: '';   width: 6px; height: 6px;   background: var(--rvp-red);   border-radius: 50%;   flex-shrink: 0; }  \/* \u2500\u2500 SECTION HEAD \u2500\u2500 *\/ .rvp-section-head { max-width: 720px; margin-bottom: var(--rvp-sp8); } .rvp-section-head h2 {   font-family: var(--rvp-font-display);   font-size: clamp(1.9rem, 3.6vw, 2.8rem);   font-weight: 700;   letter-spacing: -0.025em;   line-height: 1.08;   margin: 0 0 var(--rvp-sp5); } .rvp-section-head--dark h2  { color: var(--rvp-text-dark); } .rvp-section-head--dark .rvp-lead { color: var(--rvp-text-gray); } .rvp-section-head--light h2  { color: var(--rvp-text); } .rvp-section-head--light .rvp-lead { color: var(--rvp-text-muted); }  .rvp-lead {   font-family: var(--rvp-font-body);   font-size: clamp(1rem,1.6vw,1.125rem);   line-height: 1.65;   max-width: 56ch;   margin: 0; }  \/* \u2500\u2500 BOTONES \u2500\u2500 *\/ .rvp-btn {   display: inline-flex;   align-items: center;   justify-content: center;   gap: var(--rvp-sp3);   padding: 14px 24px;   border-radius: var(--rvp-r-pill);   font-family: var(--rvp-font-body);   font-weight: 500;   font-size: 14px;   letter-spacing: 0.04em;   text-transform: uppercase;   text-decoration: none;   cursor: pointer;   border: none;   transition: transform 220ms var(--rvp-ease), background 220ms var(--rvp-ease), box-shadow 220ms var(--rvp-ease);   white-space: nowrap; } .rvp-btn--primary { background: var(--rvp-red); color: #fff; box-shadow: 0 6px 24px rgba(232,52,75,0.28); } .rvp-btn--primary:hover { background: var(--rvp-red-deep); transform: translateY(-2px); box-shadow: 0 10px 32px rgba(232,52,75,0.42); color: #fff; } .rvp-btn--ghost { background: transparent; color: #fff; border: 1px solid rgba(255,255,255,0.22); } .rvp-btn--ghost:hover { border-color: #fff; background: rgba(255,255,255,0.04); color: #fff; } .rvp-btn--inverted { background: #fff; color: var(--rvp-red); box-shadow: 0 8px 28px rgba(0,0,0,0.22); } .rvp-btn--inverted:hover { transform: translateY(-3px); box-shadow: 0 14px 36px rgba(0,0,0,0.3); background: #F9F9F9; color: var(--rvp-red-deep); }  \/* \u2500\u2500 REVEAL ANIMATION \u2500\u2500 *\/ .rvp-reveal {   opacity: 0;   transform: translateY(22px);   transition: opacity 650ms var(--rvp-ease), transform 650ms var(--rvp-ease); } .rvp-reveal.is-vis { opacity: 1; transform: translateY(0); } .rvp-reveal:nth-child(2) { transition-delay: 80ms; } .rvp-reveal:nth-child(3) { transition-delay: 160ms; } .rvp-reveal:nth-child(4) { transition-delay: 240ms; } .rvp-reveal:nth-child(5) { transition-delay: 300ms; } .rvp-reveal:nth-child(6) { transition-delay: 360ms; }  \/* \u2500\u2500 FADE-UP (hero) \u2500\u2500 *\/ @keyframes rvp-fadeup {   from { opacity:0; transform:translateY(20px); }   to   { opacity:1; transform:translateY(0); } } .rvp-fu   { animation: rvp-fadeup 700ms var(--rvp-ease) both; } .rvp-fu-1 { animation-delay: 80ms; } .rvp-fu-2 { animation-delay: 180ms; } .rvp-fu-3 { animation-delay: 280ms; } <\/style>  <script> \/* \u2500\u2500 REVEAL OBSERVER GLOBAL \u2500\u2500 *\/ (function(){   if (!('IntersectionObserver' in window)) {     document.querySelectorAll('.rvp-reveal').forEach(function(el){ el.classList.add('is-vis'); });     return;   }   var obs = new IntersectionObserver(function(entries){     entries.forEach(function(entry){       if (entry.isIntersecting) {         entry.target.classList.add('is-vis');         obs.unobserve(entry.target);       }     });   }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });   document.querySelectorAll('.rvp-reveal').forEach(function(el){ obs.observe(el); }); })(); <\/script>","footnotes":""},"class_list":["post-5472","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/pages\/5472","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/comments?post=5472"}],"version-history":[{"count":10,"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/pages\/5472\/revisions"}],"predecessor-version":[{"id":6733,"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/pages\/5472\/revisions\/6733"}],"wp:attachment":[{"href":"https:\/\/ruvic.ai\/en\/wp-json\/wp\/v2\/media?parent=5472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}