// Diagrama aprobado de #/ruta. Datos tal cual; render en SVG 1180×610.
const RM_WA = "51933764167";
const RM_IC = {
 personas:'<circle cx="-6" cy="-5" r="4"/><circle cx="6" cy="-5" r="4"/><path d="M-14 9c0-6 4-8 8-8s8 2 8 8M-2 9c0-6 4-8 8-8s8 2 8 8"/>',
 empresa:'<path d="M-11 11V-9l9-4v24M-2 11V-4l13 4v11M-14 11h28M-7-4h0M-7 1h0M-7 6h0M4 3h0M4 7h0"/>',
 comiteInv:'<circle cx="0" cy="0" r="11"/><path d="M0 0V-11M0 0l9 6"/>',
 vigilancia:'<path d="M-14 0c4-7 9-10 14-10s10 3 14 10c-4 7-9 10-14 10S-10 7-14 0z"/><circle cx="0" cy="0" r="4"/>',
 fondo:'<ellipse cx="0" cy="-8" rx="11" ry="4"/><path d="M-11-8v6c0 2 5 4 11 4s11-2 11-4v-6M-11-2v6c0 2 5 4 11 4s11-2 11-4v-6M-11 4v5c0 2 5 4 11 4s11-2 11-4V4"/>',
 caja:'<rect x="-12" y="-11" width="24" height="22" rx="3"/><circle cx="0" cy="0" r="5"/><path d="M0-5v2M5 0h-2"/>',
 salvavidas:'<circle cx="0" cy="0" r="12"/><circle cx="0" cy="0" r="5"/><path d="M-8.5-8.5l5 5M8.5-8.5l-5 5M-8.5 8.5l5-5M8.5 8.5l-5-5"/>',
 asamblea:'<circle cx="-9" cy="-7" r="3"/><circle cx="0" cy="-9" r="3"/><circle cx="9" cy="-7" r="3"/><path d="M-14 1h28l-3 9h-22z"/>',
 ciclo:'<path d="M-10-3a10 10 0 0 1 18-4M10 3a10 10 0 0 1-18 4M8-11v4h-4M-8 11V7h4"/>',
 paquete:'<path d="M-12-6l12-6 12 6v12l-12 6-12-6zM-12-6l12 6 12-6M0 0v12"/>',
 etiqueta:'<path d="M-12-12h11l13 13-11 11-13-13z"/><circle cx="-6" cy="-6" r="2"/>',
 estrellas:'<path d="M-8-4l2 4 4 .5-3 3 .8 4-3.8-2-3.8 2 .8-4-3-3 4-.5zM8-4l2 4 4 .5-3 3 .8 4-3.8-2-3.8 2 .8-4-3-3 4-.5z"/>',
 lupa:'<circle cx="-3" cy="-3" r="8"/><path d="M3 3l9 9"/>'
};
const RM_SIDE = {
 prov:{l:"Proveedor de precios",s:"Valoriza las inversiones",ic:"etiqueta",t:"Proveedor de precios",d:"Valoriza las inversiones del fondo con una metodología independiente; de ese valor depende el valor de tu cuota.",a:"Si el valor de tu cuota no te cuadra, pedimos la metodología y la valorización."},
 clas:{l:"Clasificadora de riesgo",s:"Si aplica",ic:"estrellas",t:"Clasificadora de riesgo",d:"Empresa autorizada por la SMV que califica el riesgo de crédito de bonos, papeles comerciales, valores de titulización o cuotas de fondos, y revisa su calificación periódicamente. En una oferta pública de deuda la norma exige, por regla, dos clasificaciones de clasificadoras distintas. En oferta privada es opcional. Una baja en la calificación es una señal de alerta para el inversionista.",a:"Revisamos la clasificación, su vigencia, su independencia y te avisamos si baja."},
 aud:{l:"Auditor externo",s:"Si aplica",ic:"lupa",t:"Auditor externo",d:"Audita los estados financieros anuales. Es obligatorio en las entidades supervisadas y en la oferta pública; en la oferta privada depende de lo pactado.",a:"Revisamos el informe del auditor y sus observaciones."}
};
const RM_S = {
 fondo:{tab:"SAF: fondos de inversión",wa:"Hola, tengo una inversión en un fondo y quiero revisar mi caso",
  pub:"Oferta pública: el fondo y su reglamento están inscritos en la SMV, que supervisa a la SAF y atiende tus denuncias.",
  priv:"Oferta privada: el fondo se ofrece solo a inversionistas que cumplen los requisitos. La SMV no revisa la oferta ni el reglamento; la SAF sigue supervisada.",
  nodes:[
   {id:"smv",x:570,y:62,inst:"SMV",l:"Superintendencia del Mercado de Valores",t:"SMV",d:"Autoriza y supervisa a la SAF. En oferta pública inscribe el fondo y su reglamento, y recibe denuncias de los partícipes.",dp:"En un fondo privado la SMV no revisa la oferta ni el reglamento; supervisa a la SAF como entidad.",a:"Preparamos tu denuncia ante la SMV con la prueba y el plazo correctos."},
   {id:"saf",x:390,y:190,ic:"empresa",l:"SAF",s:"Administradora",t:"Sociedad administradora de fondos",d:"Gestiona el fondo y debe actuar en interés de los partícipes. Te informa y responde tus reclamos.",a:"Reclamamos por escrito ante la SAF y controlamos su plazo."},
   {id:"inv",x:130,y:340,ic:"personas",l:"Partícipes",s:"Tú y otros inversionistas",t:"Partícipes",d:"Compras cuotas del fondo. Tus derechos están en el reglamento de participación y en tu contrato de suscripción.",a:"Revisamos el reglamento y el contrato antes de que inviertas."},
   {id:"fondo",x:390,y:340,ic:"fondo",l:"Fondo de inversión",s:"Reglamento de participación",t:"El fondo",d:"Patrimonio separado de la SAF. El reglamento fija comisiones, plazo, política de inversiones y cómo salir.",a:"Te explicamos el reglamento en simple: costos, plazos y salidas."},
   {id:"comite",x:660,y:340,ic:"comiteInv",l:"Comité de inversiones",s:"Decide las inversiones",t:"Comité de inversiones",d:"Decide en qué invierte el fondo, dentro de la política de inversiones del reglamento.",a:"Revisamos si las inversiones respetan la política del reglamento."},
   {id:"asam",x:130,y:500,ic:"asamblea",l:"Asamblea de partícipes",s:"Decisiones importantes",t:"Asamblea de partícipes",d:"Aprueba cambios del reglamento, aumentos de capital, cambio de administradora o liquidación.",a:"Revisamos la agenda, preparamos tu voto y te representamos."},
   {id:"cust",x:390,y:500,ic:"caja",l:"Custodio",s:"Guarda los activos",t:"Custodio",d:"Guarda los valores del fondo separados de los de la SAF.",a:"Si hay dudas sobre los activos, pedimos la información por escrito."},
   {id:"vig",x:660,y:500,ic:"vigilancia",l:"Comité de vigilancia",s:"Vigila a la SAF",t:"Comité de vigilancia",d:"Representa a los partícipes y vigila que la SAF cumpla el reglamento.",a:"Te ayudamos a llevar tus observaciones al comité."}],
  side:["prov","clas","aud"],
  edges:[["inv","fondo","Aporte"],["fondo","inv","Cuotas",1],["saf","fondo","Administra"],["fondo","comite","Política de inversiones"],["inv","asam","Votan"],["fondo","cust","Custodia",0,"b"],["vig","comite","Vigila"],["saf","smv","Supervisión",0,"d"]]},
 fm:{tab:"SAF: fondos mutuos",wa:"Hola, tengo una inversión en un fondo mutuo y quiero revisar mi caso",
  pub:"Los fondos mutuos son de oferta pública: el fondo, su reglamento y su prospecto están inscritos en la SMV. Entras y sales con suscripciones y rescates.",
  priv:"No existen fondos mutuos de oferta privada: si te ofrecen uno «privado», revisa con cuidado quién lo ofrece y qué es realmente.",
  nodes:[
   {id:"smv",x:570,y:62,inst:"SMV",l:"Superintendencia del Mercado de Valores",t:"SMV",d:"Autoriza a la SAF, inscribe el fondo mutuo y supervisa a la SAF y a sus distribuidores. Recibe denuncias de los partícipes.",a:"Preparamos tu denuncia ante la SMV o el Indecopi."},
   {id:"dist",x:130,y:190,ic:"personas",l:"Distribuidor o agente colocador",s:"Te ofrece el fondo",t:"Distribuidor o agente colocador",d:"Banco, aplicación o agente que te vende el fondo por cuenta de la SAF. Debe darte el prospecto y evaluar tu perfil.",a:"Revisamos qué te ofrecieron y si te dieron la información obligatoria."},
   {id:"saf",x:390,y:190,ic:"empresa",l:"SAF",s:"Administradora",t:"Sociedad administradora de fondos",d:"Gestiona el fondo mutuo, calcula el valor cuota y te envía tu estado de cuenta.",a:"Reclamamos por escrito ante la SAF y controlamos su plazo."},
   {id:"inv",x:130,y:340,ic:"personas",l:"Partícipes",s:"Tú y otros inversionistas",t:"Partícipes",d:"Suscribes cuotas y puedes rescatarlas según el reglamento. Tus derechos están en el reglamento, el prospecto simplificado y el contrato.",a:"Revisamos el prospecto, el reglamento y tu perfil antes de invertir."},
   {id:"fondo",x:390,y:340,ic:"fondo",l:"Fondo mutuo",s:"Reglamento y prospecto",t:"El fondo mutuo",d:"Patrimonio separado de la SAF. El reglamento fija comisiones, plazos de rescate y política de inversiones; los cambios importantes te dan derecho a salir sin comisión.",a:"Te avisamos de los cambios de reglas y de tu derecho a salir."},
   {id:"comite",x:660,y:340,ic:"comiteInv",l:"Comité de inversiones",s:"Decide las inversiones",t:"Comité de inversiones",d:"Decide en qué invierte el fondo dentro de su política de inversiones.",a:"Revisamos si las inversiones respetan la política del reglamento."},
   {id:"cust",x:390,y:500,ic:"caja",l:"Custodio",s:"Guarda los activos",t:"Custodio",d:"Guarda los valores del fondo separados de los de la SAF.",a:"Si hay dudas sobre los activos, pedimos la información por escrito."}],
  side:["prov","clas","aud"],
  edges:[["dist","inv","Te ofrece el fondo"],["inv","fondo","Suscripción"],["fondo","inv","Rescate",1],["saf","fondo","Administra"],["fondo","comite","Política de inversiones"],["fondo","cust","Custodia",0,"b"],["saf","smv","Supervisión",0,"d"],["dist","smv","",0,"d"]]},
 sab:{tab:"SAB: acciones y bonos",wa:"Hola, invierto en bolsa a través de una SAB y quiero revisar mi caso",
  pub:"Oferta pública: los valores están inscritos y se negocian en la Bolsa de Valores de Lima. La SMV supervisa a la SAB, a la Bolsa y a CAVALI.",
  priv:"Oferta privada o valores no inscritos: se negocian fuera de rueda, con menos información y protección. La SAB sigue supervisada.",
  nodes:[
   {id:"smv",x:570,y:62,inst:"SMV",l:"Superintendencia del Mercado de Valores",t:"SMV",d:"Supervisa a la SAB, a la Bolsa y a CAVALI. Recibe denuncias y puede ordenar medidas correctivas.",dp:"En valores no inscritos la SMV no revisa la oferta; sigue supervisando la conducta de la SAB.",a:"Preparamos tu denuncia ante la SMV o el Indecopi."},
   {id:"inv",x:120,y:340,ic:"personas",l:"Inversionista",s:"Cliente de la SAB",t:"Tú, cliente de la SAB",d:"Das órdenes y recibes pólizas y estados de cuenta. Tus derechos están en el contrato de intermediación.",a:"Revisamos tu contrato, tu perfil de riesgo y tus comisiones."},
   {id:"sab",x:350,y:340,ic:"empresa",l:"SAB",s:"Contrato de intermediación",t:"Sociedad agente de bolsa",d:"Ejecuta tus órdenes, cobra comisiones y debe informarte. Toda operación debe tener una orden tuya.",a:"Cotejamos órdenes, pólizas y estado de cuenta; reclamamos operaciones no autorizadas."},
   {id:"bvl",x:590,y:340,inst:"BVL",l:"Bolsa de Valores de Lima",s:"Rueda de bolsa",lp:"Fuera de rueda",sp:"Negociación directa",t:"Bolsa de Valores de Lima",d:"El mercado donde la SAB compra o vende tus acciones y bonos inscritos.",dp:"Los valores no inscritos se negocian fuera de rueda, sin las reglas ni la información de la Bolsa.",a:"Te explicamos cómo se forma el precio y qué pasa con tu orden."},
   {id:"cav",x:830,y:340,inst:"CAVALI",l:"CAVALI",s:"Registro y liquidación",t:"CAVALI",d:"Registra a tu nombre los valores que compras y liquida las operaciones.",a:"Conciliamos lo que dice tu SAB con tu registro en CAVALI."},
   {id:"fg",x:350,y:500,ic:"salvavidas",l:"Fondo de Garantía",s:"Respaldo del cliente",t:"Fondo de Garantía",d:"Respalda a los clientes cuando la SAB no cumple una resolución firme.",a:"Gestionamos el cobro con el Fondo de Garantía cuando corresponde."},
   {id:"emi",x:590,y:500,ic:"empresa",l:"Emisor",s:"Empresa que emite",t:"Emisor",d:"La empresa que emitió las acciones o bonos. Informa hechos de importancia y paga dividendos o intereses.",a:"Revisamos el cobro de tus dividendos e intereses."}],
  side:["clas","aud"],
  edges:[["inv","sab","Órdenes"],["sab","inv","Pólizas y estado de cuenta",1],["sab","bvl","Negocia"],["bvl","cav","Liquida",0,"b"],["emi","bvl","Acciones y bonos",0,"b"],["fg","sab","Respalda"],["sab","smv","Supervisión",0,"d"],["bvl","smv","",0,"d","pub"],["cav","smv","",0,"d","pub"]]},
 tit:{tab:"Titulización",wa:"Hola, tengo bonos o certificados de una titulización y quiero revisar mi caso",
  pub:"Oferta pública: la emisión está inscrita en la SMV, que supervisa a la titulizadora y la información del patrimonio.",
  priv:"Oferta privada: solo para inversionistas institucionales. La SMV no revisa la emisión ni atiende reclamos sobre ella; la titulizadora sigue supervisada.",
  nodes:[
   {id:"smv",x:640,y:62,inst:"SMV",l:"Superintendencia del Mercado de Valores",t:"SMV",d:"Supervisa a la titulizadora y, en oferta pública, inscribe la emisión y vigila la información del patrimonio.",dp:"En oferta privada la SMV no revisa la emisión ni atiende reclamos sobre ella.",a:"Preparamos tu reclamo o denuncia contra la titulizadora."},
   {id:"titu",x:340,y:190,ic:"empresa",l:"Titulizadora",s:"Administra el patrimonio",t:"Sociedad titulizadora",d:"Administra el patrimonio, informa a los inversionistas y convoca a las asambleas.",a:"Pedimos información y reclamamos si llega tarde o incompleta."},
   {id:"ori",x:110,y:340,ic:"empresa",l:"Originador",s:"Transfiere sus activos",t:"Originador",d:"La empresa que transfiere cartera, flujos o inmuebles para respaldar la emisión.",a:"Revisamos si la transferencia aísla de verdad los activos."},
   {id:"pat",x:340,y:340,ic:"paquete",l:"Patrimonio",s:"Fideicomiso de titulización",t:"Patrimonio fideicometido",d:"Patrimonio separado del originador. De él salen los pagos, en el orden que fija el acto constitutivo.",a:"Te explicamos el prospecto: prelación, garantías y orden de pagos."},
   {id:"sab",x:580,y:340,ic:"empresa",l:"SAB",s:"Coloca los valores",sp:"Coloca entre institucionales",t:"SAB colocadora",d:"Coloca los bonos o certificados entre los inversionistas.",a:"Revisamos qué te ofrecieron y si coincide con el prospecto."},
   {id:"inv",x:820,y:340,ic:"personas",l:"Inversionistas",s:"Bonos o certificados",sp:"Institucionales",t:"Tú, inversionista",d:"Compras bonos o certificados y cobras según la cascada de pagos.",a:"Auditamos tus cobros y vigilamos tus plazos."},
   {id:"serv",x:340,y:500,ic:"ciclo",l:"Servidor (cobranza)",s:"Cobra los flujos",t:"Servidor",d:"Así llama la Ley del Mercado de Valores a quien cobra los flujos de los activos y los entrega al patrimonio. Muchas veces es el propio originador.",a:"Revisamos que los flujos lleguen al patrimonio."},
   {id:"asam",x:820,y:500,ic:"asamblea",l:"Asamblea de fideicomisarios",s:"Dispensas y cambios",t:"Asamblea de fideicomisarios",d:"Decide dispensas, cambios del acto constitutivo y el cambio de fiduciario.",a:"Preparamos tu voto y te representamos."}],
  side:["clas","aud"],
  edges:[["ori","pat","Transfiere activos",0,"b"],["titu","pat","Administra"],["pat","sab","Emite valores",0,"b"],["sab","inv","Coloca"],["serv","pat","Flujos",0,"b"],["inv","asam","Votan"],["titu","smv","Supervisión",0,"d"]]}
};
const RM_KEYS = Object.keys(RM_S);
const RM_COL = { f: "#26426E", b: "#C39D77", d: "#5B79A8" };
const rmWrap = (s, n) => { const out = []; let cur = ""; s.split(" ").forEach((w) => { const nx = cur ? cur + " " + w : w; if (nx.length > n && cur) { out.push(cur); cur = w; } else cur = nx; }); if (cur) out.push(cur); return out; };
const rmClip = (a, b) => { const dx = b.x - a.x, dy = b.y - a.y; const t = Math.min(dx ? 98 / Math.abs(dx) : Infinity, dy ? 41 / Math.abs(dy) : Infinity); return { x: a.x + dx * t, y: a.y + dy * t }; };

function RmNode({ n, num, side, sel, priv, onOpen }) {
  const L = priv && n.lp ? n.lp : n.l;
  const Sb = priv && n.sp ? n.sp : n.s;
  const x0 = n.x - 94, y0 = n.y - 37;
  const tl = rmWrap(L, 17), sl = Sb ? rmWrap(Sb, 21).slice(0, 2) : [];
  const h = tl.length * 15 + sl.length * 14 + (sl.length ? 2 : 0);
  const top = n.y - h / 2;
  const tx = n.inst ? x0 + 74 : x0 + 60;
  const key = (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onOpen(); } };
  return <g className={"node" + (sel ? " sel" : "")} tabIndex="0" role="button" aria-label={"Actor " + num + ": " + n.t} onClick={onOpen} onKeyDown={key}>
    <rect className="card" x={x0} y={y0} width="188" height="74" rx="12" fill="#FFFFFF" stroke="#DDD6C8" strokeWidth="1" filter="url(#rmShadow)"></rect>
    {n.inst ? <g><rect x={x0 + 10} y={n.y - 17} width="56" height="34" rx="4" fill="#16284A"></rect><text x={x0 + 38} y={n.y + 5} textAnchor="middle" fill="#FFFFFF" style={{ font: "400 " + (n.inst.length > 4 ? 12 : 15) + "px var(--rm-display)" }}>{n.inst}</text></g>
      : <g><circle cx={x0 + 34} cy={n.y} r="20" fill={side ? "#F4EBDD" : "#26426E"}></circle><g transform={"translate(" + (x0 + 34) + " " + n.y + ")"} fill="none" stroke={side ? "#8C6A43" : "#FFFFFF"} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" dangerouslySetInnerHTML={{ __html: RM_IC[n.ic] }}></g></g>}
    {tl.map((t, i) => <text key={"t" + i} className="t1" x={tx} y={top + 11 + i * 15}>{t}</text>)}
    {sl.map((t, i) => <text key={"s" + i} className="t2" x={tx} y={top + tl.length * 15 + 2 + 10 + i * 14}>{t}</text>)}
    <circle cx={x0 + 188} cy={y0} r="10" fill="#C39D77"></circle>
    <text x={x0 + 188} y={y0 + 4} textAnchor="middle" style={{ font: "700 11px var(--rm-body)" }} fill="#16284A">{num}</text>
  </g>;
}

function RouteMap() {
  const [k, setK] = React.useState(() => { const h = (location.hash.match(/^#\/?ruta\/([a-z]+)/) || [])[1]; if (RM_S[h]) return h; const v = sessionStorage.getItem("lex-ruta4"); return RM_S[v] ? v : RM_KEYS[0]; });
  const [mode, setMode] = React.useState("pub");
  const [sel, setSel] = React.useState(null);
  const sc = RM_S[k], priv = mode === "priv";
  React.useEffect(() => { setSel(null); sessionStorage.setItem("lex-ruta4", k); }, [k, mode]);
  React.useEffect(() => { const f = (e) => { if (e.key === "Escape") setSel(null); }; addEventListener("keydown", f); return () => removeEventListener("keydown", f); }, []);
  const byId = {}; sc.nodes.forEach((n) => { byId[n.id] = n; });
  const sides = sc.side.map((id, i) => ({ ...RM_SIDE[id], id: "side-" + id, x: 1064, y: 240 + i * 112 }));
  const edges = sc.edges.filter((e) => !(priv && e[5] === "pub"));
  const lines = edges.map((e) => {
    const A = byId[e[0]], B = byId[e[1]];
    let off = { x: 0, y: 0 }, second = false;
    const partner = edges.find((o) => o !== e && o[0] === e[1] && o[1] === e[0]);
    if (partner) {
      const first = e[3] ? partner : e; second = !!e[3];
      const fa = byId[first[0]], fb = byId[first[1]];
      const len = Math.hypot(fb.x - fa.x, fb.y - fa.y) || 1;
      const nx = -(fb.y - fa.y) / len, ny = (fb.x - fa.x) / len;
      const s = second ? 9 : -9; off = { x: nx * s, y: ny * s };
    }
    const p1 = rmClip(A, B), p2 = rmClip(B, A);
    const kind = e[4] === "b" ? "b" : e[4] === "d" ? "d" : "f";
    const horiz = Math.abs(A.y - B.y) < 1;
    const lx = (p1.x + p2.x) / 2 + (horiz ? 0 : off.x), ly = horiz ? A.y + (off.y > 0 ? 50 : -50) : (p1.y + p2.y) / 2 + off.y;
    return { e, kind, x1: p1.x + off.x, y1: p1.y + off.y, x2: p2.x + off.x, y2: p2.y + off.y, lx, ly };
  });
  const all = sc.nodes.map((n, i) => ({ n, num: i + 1, side: false })).concat(sides.map((n, i) => ({ n, num: sc.nodes.length + i + 1, side: true })));
  const cur = sel && all.find((x) => x.n.id === sel);
  return <section className="rmap">
    <div className="rm-wrap"><div className="rm-k">Ruta de la inversión</div><h1 className="rm-h1">¿Dónde está tu inversión?</h1>
      <p className="rm-lead">Elige dónde inviertes y si es una oferta pública o privada. Toca cada actor para saber qué hace, qué derechos tienes frente a él y en qué te ayudamos.</p>
      <div className="rm-bar">
        <div className="rm-tabs" role="tablist">{RM_KEYS.map((id) => <button key={id} role="tab" aria-selected={id === k} className={id === k ? "on" : ""} onClick={() => setK(id)}>{RM_S[id].tab}</button>)}</div>
        <div className="rm-seg"><button className={!priv ? "on" : ""} onClick={() => setMode("pub")}>Oferta pública</button><button className={priv ? "on" : ""} onClick={() => setMode("priv")}>Oferta privada</button></div>
      </div>
      <div className="rm-note">{sc[mode]}</div>
      <div className="rm-stage"><div className="rm-scroll">
        <svg className="rm-svg" viewBox="0 0 1180 610" role="img" aria-label={"Mapa de actores: " + sc.tab}>
          <defs>
            <filter id="rmShadow" x="-10%" y="-20%" width="120%" height="150%"><feDropShadow dx="0" dy="3" stdDeviation="4" floodColor="#16284A" floodOpacity="0.08"></feDropShadow></filter>
            {Object.keys(RM_COL).map((c) => <marker key={c} id={"rmA" + c} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" fill={RM_COL[c]}></path></marker>)}
          </defs>
          <rect x="16" y="14" width="930" height="100" rx="10" fill="#EEF1F6"></rect>
          <text className="zone" x="32" y="36">SUPERVISIÓN</text>
          <rect x="16" y="128" width="930" height="466" rx="10" fill="#FFFFFF" stroke="#E8E2D6"></rect>
          <text className="zone" x="32" y="150">{priv ? "OFERTA PRIVADA" : "OFERTA PÚBLICA"}</text>
          <rect x="958" y="128" width="212" height="466" rx="10" fill="none" stroke="#D2C3AE" strokeDasharray="5 4"></rect>
          <text className="zone" x="974" y="150">SI APLICA</text>
          {lines.map((l, i) => <line key={i} x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} stroke={RM_COL[l.kind]} strokeWidth="1.8" strokeDasharray={l.kind === "d" ? "6 5" : undefined} markerEnd={"url(#rmA" + l.kind + ")"}></line>)}
          {all.map(({ n, num, side }) => <RmNode key={n.id} n={n} num={num} side={side} priv={priv} sel={sel === n.id} onOpen={() => setSel(n.id)} />)}
          {lines.filter((l) => l.e[2]).map((l, i) => { const w = l.e[2].length * 6.4 + 18; return <g key={"lb" + i}><rect x={l.lx - w / 2} y={l.ly - 11} width={w} height="22" rx="11" fill="#FFFFFF" stroke="#E8E2D6"></rect><text className="el" x={l.lx} y={l.ly + 4} textAnchor="middle">{l.e[2]}</text></g>; })}
        </svg>
      </div>
      {cur && <div className="rm-pop" role="dialog" aria-label={cur.n.t}>
        <button className="x" aria-label="Cerrar" onClick={() => setSel(null)}>×</button>
        <div className="n">{"Actor " + cur.num + (cur.side ? " · si aplica" : "")}</div>
        <h3>{cur.n.t}</h3>
        <p>{priv && cur.n.dp ? cur.n.dp : cur.n.d}</p>
        <div className="ay"><b>Cómo te ayudamos.</b> {cur.n.a}</div>
        <a href={"https://wa.me/" + RM_WA + "?text=" + encodeURIComponent(sc.wa)} target="_blank" rel="noopener">Consultar por WhatsApp</a>
      </div>}
      </div>
      <p className="rm-swipe">Desliza el mapa hacia los lados para verlo completo.</p>
      <div className="rm-legend"><span><i></i>Flujo de la operación</span><span><i className="b"></i>Activos y valores</span><span><i className="d"></i>Supervisión de la SMV</span><span>Recuadro punteado: si aplica</span></div>
    </div>
  </section>;
}

function RutaPage() {
  return <>
    <RouteMap />
    <ClosingBand ctx="ruta" />
  </>;
}

const RUTA_SUM = [["sab", "SAB: acciones y bonos"], ["fondo", "SAF: fondos de inversión"], ["fm", "SAF: fondos mutuos"], ["tit", "Titulización"]];
function RutaSummary() {
  const open = (k) => (e) => { e.preventDefault(); sessionStorage.setItem("lex-ruta4", k); go("/ruta"); };
  return <section className="white sec hs">
    <div className="wrap">
      <Label>La ruta</Label>
      <h2 className="h2 rv">¿Dónde está tu inversión?</h2>
      <p className="lead" style={{ marginTop: 16 }}>Quién participa en cada operación, qué derechos tienes frente a cada actor y dónde te ayudamos.</p>
      <div className="rsum four">{RUTA_SUM.map(([k, t]) => <a key={k} href="#/ruta" onClick={open(k)} className="rv"><b>{t}</b><span className="more">Ver el mapa <Icon name="arrow-right" size={14} /></span></a>)}</div>
    </div>
  </section>;
}

const RutaLink = () => <section className="ivory2 rlink">
  <div className="wrap rlink-in">
    <p><b>¿Dónde está tu inversión?</b> Quién participa en una SAB, un fondo o una titulización.</p>
    <a className="tlink" href="#/ruta">Ver el mapa <Icon name="arrow-right" size={14} /></a>
  </div>
</section>;

Object.assign(window, { RouteMap, RutaPage, RutaSummary, RutaLink });
