Files
Creeer-Web/docs/superpowers/plans/2026-07-31-coherencia-ilustraciones-hilo.md
T

25 KiB
Raw Blame History

Coherencia de las ilustraciones + hilo conductor al centro — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Que cada ilustración exprese el mensaje de su sección y la narrativa de marca (Complejidad → Enfoque → Claridad), y que el hilo dorado sea visible bajando por el centro, tras el texto.

Architecture: El hilo (HiloConductor) se mueve del canal izquierdo (donde vive hoy, right-full, hidden 2xl:block) al centro y se muestra en todos los breakpoints; para que no cruce/dañe la lectura, el contenido se levanta por encima de él subiendo Container a relative z-20 (fondos de sección z-auto < hilo z-10 < texto z-20). IlustracionInflexion se rehace como una curva que se dobla en el punto (sin fork, para dejar de duplicar a ParaQuien). Nudo/Bifurcación/Convergencia unifican sus grosores a la escala 1.5 / 2 / 3. El nudo se reciente en Dolores para que el hilo central lo atraviese.

Tech Stack: Next.js 14 App Router (output: 'export'), TypeScript, Tailwind, Framer Motion, Vitest + jsdom + Testing Library.

Global Constraints

  • Gestor de paquetes: pnpm. Nunca npm.
  • Idioma: copy, docs y mensajes de commit en español; comentarios de código en inglés.
  • No se toca el copy de lib/content.ts. Ninguna tarea edita ese archivo.
  • No se reordenan las secciones de app/page.tsx.
  • Colores por token, nunca hex suelto: text-dorado, text-azul-profundo, text-gris-medio.
  • El wordmark cre≡er va siempre en minúsculas y sólo se renderiza vía <Wordmark />.
  • No se agrega escasez al hero. El test negativo Hero.test.tsx (cupos|cohorte|generación fundadora) debe seguir pasando.
  • Toda animación pasa por usePrefersReducedMotion() / useEnVista(). La rama reducida SIEMPRE renderiza elementos SVG planos (<path>, <line>), nunca motion.* neutralizados (el bug del dash-scaffolding ya documentado).
  • Ilustraciones decorativas: aria-hidden="true" y focusable="false" en el <svg>.
  • Escala tipográfica de trazo (nueva, fija): base 2, énfasis 3, detalle fino 1.5. Excepción única y documentada: SecuenciaClaridad resuelve en las barras reales del ≡ (grosor de LINEAS_SIMBOLO).
  • Verificación por tarea: pnpm test en verde antes de cada commit. Al final del plan, además: pnpm lint, npx tsc --noEmit y pnpm build.
  • Rama de trabajo: feat/hilo-conductor-visual (ya activa).

Estructura de archivos

Modificar:

Archivo Responsabilidad del cambio
components/primitives/HiloConductor.tsx Mover el hilo al centro, visible en todos los breakpoints, z-10, trazo más tenue/recto
components/primitives/Container.tsx Añadir relative z-20 para que el texto quede sobre el hilo
components/primitives/IlustracionInflexion.tsx Rehacer: curva que se dobla en el punto (azul → dorada), sin fork, lienzo 220×120
components/primitives/IlustracionNudo.tsx Unificar grosores de las hebras a la escala
components/primitives/IlustracionBifurcacion.tsx Grosor del tronco 2.5 → 2
components/primitives/IlustracionConvergencia.tsx Grosor de la estrategia 3.5 → 3
components/sections/Dolores.tsx Recentrar el nudo para que el hilo central lo atraviese

Crear:

Archivo Responsabilidad
components/primitives/__tests__/Container.test.tsx Fija el mecanismo de apilado (el contenido queda sobre el hilo)

Tests a actualizar: HiloConductor.test.tsx, IlustracionInflexion.test.tsx, IlustracionNudo.test.tsx, IlustracionBifurcacion.test.tsx, IlustracionConvergencia.test.tsx, Dolores.test.tsx.


Task 1: El hilo al centro, visible, tras el texto

Hoy el hilo vive en el canal izquierdo (right-full) y sólo aparece desde 2xl. La dueña pidió que esté en medio. Se mueve al centro, se muestra en todos los breakpoints, y se pone tras el texto subiendo Container a relative z-20 (fondos z-auto < hilo z-10 < texto z-20): el hilo se lee como una columna tenue tras la lectura, nunca cruzándola.

Files:

  • Modify: components/primitives/HiloConductor.tsx
  • Modify: components/primitives/Container.tsx
  • Modify: components/primitives/__tests__/HiloConductor.test.tsx
  • Create: components/primitives/__tests__/Container.test.tsx

Interfaces:

  • Consumes: usePrefersReducedMotion; useScroll, useSpring, motion de framer-motion.

  • Produces: HiloConductor centrado y visible (mismo nombre de export, mismos consumidores: app/page.tsx). Container con relative z-20 (mismo nombre de export).

  • Step 1: Actualizar los tests del hilo (deben fallar) y crear el test de Container

En components/primitives/__tests__/HiloConductor.test.tsx, sustituir el test sits in the margin band beside the column, never over it por:

  it('runs down the centre of the column, not in a side gutter', () => {
    const { container } = render(<HiloConductor />);
    const cls = container.querySelector('svg')?.getAttribute('class') ?? '';
    // `left-1/2 -translate-x-1/2` anchors the thread to the column's centre;
    // the old `right-full` banished it to the left gutter, which is why the
    // thread read as off to the side instead of as the page's spine.
    expect(cls).toContain('left-1/2');
    expect(cls).toContain('-translate-x-1/2');
    expect(cls).not.toContain('right-full');
  });

Y sustituir el test is hidden below the breakpoint that guarantees a safe margin por:

  it('renders on every breakpoint, not only on very wide screens', () => {
    const { container } = render(<HiloConductor />);
    const wrapperClass = container.firstElementChild?.className ?? '';
    // The thread is the brand's through-line; it belongs in the middle on a
    // phone too. Legibility is handled by layering it behind the text, not by
    // hiding it below a breakpoint.
    expect(wrapperClass).not.toContain('hidden');
    expect(wrapperClass).not.toContain('2xl:block');
  });

Los demás tests del archivo (decorativo, un solo path, absolute no fixed, pointer-events-none, nivel de apilado z-\d+, rama reducida con <path> plano) se quedan sin cambios.

Crear components/primitives/__tests__/Container.test.tsx:

import { render } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { Container } from '../Container';

describe('<Container />', () => {
  it('lifts its content above the conductor thread', () => {
    const { container } = render(<Container>contenido</Container>);
    const cls = container.firstElementChild?.className ?? '';
    // The thread sits at z-10; the section backgrounds are z-auto. Lifting the
    // content column to z-20 is what puts the text *above* a centred thread,
    // so the spine reads behind the reading instead of across it.
    expect(cls).toContain('relative');
    expect(cls).toMatch(/\bz-20\b/);
  });
});
  • Step 2: Correr — deben fallar

Run: pnpm test --run components/primitives/__tests__/HiloConductor.test.tsx components/primitives/__tests__/Container.test.tsx Expected: FAIL — el svg del hilo aún tiene right-full/hidden, y Container no tiene z-20.

  • Step 3: Reescribir HiloConductor.tsx

Contenido completo del archivo:

'use client';

import { motion, useScroll, useSpring } from 'framer-motion';
import { usePrefersReducedMotion } from '@/lib/motion';

// The gold spine of the page: one continuous line down the vertical centre,
// drawing itself as the reader scrolls. It is what turns ten sections into a
// single route — *claridad · dirección · crecimiento* made visible, per the
// Manual de Identidad Visual.
//
// Centred, never in a side gutter: the brand's through-line belongs in the
// middle, on every breakpoint. It sits ABOVE the section backgrounds (z-10)
// but BELOW the text, which `Container` lifts to z-20 — so the thread reads
// as a faint watermark spine behind the reading, never crossing it.
//
// Page-level useScroll() with no target ref on purpose: no element measuring,
// no "container has a static position" warnings, one listener for the page.

const TRAZO =
  'M50 0 C 42 200, 58 400, 50 600 C 42 800, 58 1000, 50 1200';

export function HiloConductor({ className = '' }: { className?: string }) {
  const reduced = usePrefersReducedMotion();
  const { scrollYProgress } = useScroll();
  const avance = useSpring(scrollYProgress, { stiffness: 90, damping: 30, restDelta: 0.001 });

  const wrapper = `pointer-events-none absolute inset-0 z-10 ${className}`;

  // Plain <path> for reduced motion: motion.path applies dash scaffolding even
  // without initial/animate and would leave the thread invisible.
  const trazo = reduced ? (
    <path d={TRAZO} fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" />
  ) : (
    <motion.path
      d={TRAZO}
      fill="none"
      stroke="currentColor"
      strokeWidth={1.5}
      strokeLinecap="round"
      style={{ pathLength: avance }}
    />
  );

  return (
    <div className={wrapper}>
      {/* Mirrors Container's own centring (`mx-auto max-w-content`) so the
          thread is measured from the real column edge and stays centred in it. */}
      <div className="relative mx-auto h-full w-full max-w-content">
        <svg
          className="absolute inset-y-0 left-1/2 h-full w-14 -translate-x-1/2 text-dorado/25"
          viewBox="0 0 100 1200"
          preserveAspectRatio="none"
          aria-hidden="true"
          focusable="false"
        >
          {trazo}
        </svg>
      </div>
    </div>
  );
}
  • Step 4: Añadir relative z-20 a Container.tsx

Sustituir la línea de retorno por:

  return <Tag className={`relative z-20 mx-auto w-full max-w-content px-6 md:px-12 ${className}`}>{children}</Tag>;
  • Step 5: Correr — debe pasar

Run: pnpm test --run components/primitives/__tests__/HiloConductor.test.tsx components/primitives/__tests__/Container.test.tsx Expected: PASS (8 tests del hilo + 1 de Container).

  • Step 6: Correr la suite completa y commitear

Run: pnpm test Expected: PASS (los cambios de apilado no rompen tests de sección, que verifican copy/contrato, no clases de Container).

git add components/primitives/HiloConductor.tsx components/primitives/Container.tsx components/primitives/__tests__/HiloConductor.test.tsx components/primitives/__tests__/Container.test.tsx
git commit -m "feat(hilo): el conductor baja visible por el centro, tras el texto"

Task 2: IlustracionInflexion — la curva que se dobla, sin fork

Hoy dibuja tres caminos divergentes (crecimiento / deriva / estrategia): el mismo fork que IlustracionBifurcacion. Se rehace como una sola línea que se dobla en el punto de inflexión — azul (el presente) antes del punto, dorada (la claridad) después — para que encarene el concepto de "punto de inflexión" y deje de duplicar a ParaQuien. Lienzo 220×120 (compartido con Bifurcación y Convergencia).

Files:

  • Modify: components/primitives/IlustracionInflexion.tsx
  • Modify: components/primitives/__tests__/IlustracionInflexion.test.tsx

Interfaces:

  • Consumes: useEnVista de lib/motion.

  • Produces: IlustracionInflexion({ className?: string }) (mismo nombre; la consume PuntosInflexion).

  • Step 1: Reescribir el test (debe fallar)

Contenido completo de components/primitives/__tests__/IlustracionInflexion.test.tsx:

import { render } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { IlustracionInflexion } from '../IlustracionInflexion';

describe('<IlustracionInflexion />', () => {
  it('is decorative: hidden from assistive tech', () => {
    const { container } = render(<IlustracionInflexion />);
    const svg = container.querySelector('svg');
    expect(svg).toHaveAttribute('aria-hidden', 'true');
    expect(svg).toHaveAttribute('focusable', 'false');
  });

  it('shares the unified canvas with the other scene illustrations', () => {
    const { container } = render(<IlustracionInflexion />);
    expect(container.querySelector('svg')).toHaveAttribute('viewBox', '0 0 220 120');
  });

  it('is a single bend at the inflection point, not a fork', () => {
    const { container } = render(<IlustracionInflexion />);
    // The previous version drew three diverging paths (growth / drift /
    // strategy) — the same fork as ParaQuien. The rework is one continuous
    // line that bends at the point: two segments, pre- and post-inflection.
    expect(container.querySelectorAll('path')).toHaveLength(2);
  });

  it('marks the inflection point itself', () => {
    const { container } = render(<IlustracionInflexion />);
    expect(container.querySelectorAll('circle').length).toBeGreaterThanOrEqual(1);
  });

  it('bends from the present (azul) into clarity (dorado)', () => {
    const { container } = render(<IlustracionInflexion />);
    const clases = Array.from(container.querySelectorAll('path')).map((p) => p.getAttribute('class') ?? '');
    expect(clases.some((c) => c.includes('text-azul-profundo'))).toBe(true);
    expect(clases.some((c) => c.includes('text-dorado'))).toBe(true);
  });
});
  • Step 2: Correr — debe fallar

Run: pnpm test --run components/primitives/__tests__/IlustracionInflexion.test.tsx Expected: FAIL — hoy hay 3 paths (no 2) y el viewBox es 0 0 320 180.

  • Step 3: Reescribir IlustracionInflexion.tsx

Contenido completo del archivo:

'use client';

import { motion } from 'framer-motion';
import { useEnVista } from '@/lib/motion';

// The section's own subject, drawn: the inflection point itself. One line
// rises gently (the present, azul), bends at the marked point, and from there
// climbs steeply in dorado — clarity accelerating the climb. No fork, no
// "deriva": that bifurcation belongs to ParaQuien, not here.
const ANTES = 'M10 110 C 55 104, 85 88, 110 72';
const DESPUES = 'M110 72 C 145 60, 178 24, 210 12';

export function IlustracionInflexion({ className = '' }: { className?: string }) {
  const { ref, enVista, reduced } = useEnVista();

  const punto = (
    <>
      <circle cx={110} cy={72} r={6} fill="currentColor" className="text-dorado" />
      <circle cx={110} cy={72} r={10} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={1} strokeOpacity={0.4} />
    </>
  );

  // Plain <path> under reduced motion — motion.path applies its own dash
  // scaffolding and would leave the drawing invisible.
  if (reduced) {
    return (
      <svg ref={ref} viewBox="0 0 220 120" className={className} aria-hidden="true" focusable="false">
        <path d={ANTES} fill="none" stroke="currentColor" className="text-azul-profundo" strokeWidth={2} strokeLinecap="round" />
        <path d={DESPUES} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" />
        {punto}
      </svg>
    );
  }

  const dibuja = (delay: number) => ({
    initial: { pathLength: 0 },
    animate: enVista ? { pathLength: 1 } : { pathLength: 0 },
    transition: { duration: 1.1, delay, ease: [0.22, 1, 0.36, 1] as const },
  });

  return (
    <svg ref={ref} viewBox="0 0 220 120" className={className} aria-hidden="true" focusable="false">
      <motion.path d={ANTES} fill="none" stroke="currentColor" className="text-azul-profundo" strokeWidth={2} strokeLinecap="round" {...dibuja(0)} />
      <motion.path d={DESPUES} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" {...dibuja(0.5)} />
      {punto}
    </svg>
  );
}
  • Step 4: Correr — debe pasar

Run: pnpm test --run components/primitives/__tests__/IlustracionInflexion.test.tsx Expected: PASS (5 tests).

  • Step 5: Correr la suite completa y commitear

Run: pnpm test Expected: PASS.

git add components/primitives/IlustracionInflexion.tsx components/primitives/__tests__/IlustracionInflexion.test.tsx
git commit -m "feat(inflexion): la curva que se dobla en el punto, sin fork"

Task 3: Unificar grosores a la escala 1.5 / 2 / 3

IlustracionNudo (2.5), IlustracionBifurcacion (tronco 2.5) e IlustracionConvergencia (estrategia 3.5) quedan fuera de la escala. Un test de contrato exige que todo trazo pertenezca a {1.5, 2, 3} y impulsa los cambios.

Files:

  • Modify: components/primitives/IlustracionNudo.tsx
  • Modify: components/primitives/IlustracionBifurcacion.tsx
  • Modify: components/primitives/IlustracionConvergencia.tsx
  • Modify: components/primitives/__tests__/IlustracionNudo.test.tsx
  • Modify: components/primitives/__tests__/IlustracionBifurcacion.test.tsx
  • Modify: components/primitives/__tests__/IlustracionConvergencia.test.tsx

Interfaces:

  • Sin cambios de interfaz pública. Sólo grosores.

  • Step 1: Añadir el test de escala (debe fallar)

Añadir a components/primitives/__tests__/IlustracionNudo.test.tsx, dentro del describe:

  it('keeps every stroke within the shared line-art scale', () => {
    const { container } = render(<IlustracionNudo />);
    const anchos = Array.from(container.querySelectorAll('path')).map((p) => p.getAttribute('stroke-width'));
    expect(anchos.length).toBeGreaterThan(0);
    anchos.forEach((a) => expect(['1.5', '2', '3']).toContain(a));
  });

Añadir a components/primitives/__tests__/IlustracionBifurcacion.test.tsx, dentro del describe:

  it('keeps every stroke within the shared line-art scale', () => {
    const { container } = render(<IlustracionBifurcacion />);
    const anchos = Array.from(container.querySelectorAll('path')).map((p) => p.getAttribute('stroke-width'));
    expect(anchos.length).toBeGreaterThan(0);
    anchos.forEach((a) => expect(['1.5', '2', '3']).toContain(a));
  });

Añadir a components/primitives/__tests__/IlustracionConvergencia.test.tsx, dentro del describe:

  it('keeps every stroke within the shared line-art scale', () => {
    const { container } = render(<IlustracionConvergencia />);
    const anchos = Array.from(container.querySelectorAll('path')).map((p) => p.getAttribute('stroke-width'));
    expect(anchos.length).toBeGreaterThan(0);
    anchos.forEach((a) => expect(['1.5', '2', '3']).toContain(a));
  });
  • Step 2: Correr — deben fallar

Run: pnpm test --run components/primitives/__tests__/IlustracionNudo.test.tsx components/primitives/__tests__/IlustracionBifurcacion.test.tsx components/primitives/__tests__/IlustracionConvergencia.test.tsx Expected: FAIL — 2.5 (Nudo, Bifurcación) y 3.5 (Convergencia) no están en {1.5, 2, 3}.

  • Step 3: Unificar los grosores

En components/primitives/IlustracionNudo.tsx, sustituir el array HEBRAS por grosores de la escala (la primera hebra pasa de 2.5 a 3 —énfasis— para conservar la jerarquía visual del nudo):

const HEBRAS = [
  { d: 'M30 90 C 60 20, 130 20, 140 70 C 148 112, 78 118, 70 78 C 63 44, 120 38, 150 66', ancho: 3 },
  { d: 'M20 60 C 70 110, 120 110, 160 60', ancho: 2 },
  { d: 'M40 110 C 80 40, 110 130, 155 95', ancho: 2 },
  { d: 'M25 40 C 90 70, 100 100, 165 40', ancho: 1.5 },
];

En components/primitives/IlustracionBifurcacion.tsx, cambiar el strokeWidth del tronco de 2.5 a 2 en las dos ramas (reduced y animada):

      <path d={TRONCO} fill="none" stroke="currentColor" className="text-azul-profundo" strokeWidth={2} strokeLinecap="round" />
      <motion.path d={TRONCO} fill="none" stroke="currentColor" className="text-azul-profundo" strokeWidth={2} strokeLinecap="round" {...dibuja(0)} />

En components/primitives/IlustracionConvergencia.tsx, cambiar el strokeWidth de la estrategia de 3.5 a 3 en las dos ramas:

        <path d={ESTRATEGIA} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" />
      <motion.path d={ESTRATEGIA} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" {...dibuja(0.7)} />
  • Step 4: Correr — deben pasar

Run: pnpm test --run components/primitives/__tests__/IlustracionNudo.test.tsx components/primitives/__tests__/IlustracionBifurcacion.test.tsx components/primitives/__tests__/IlustracionConvergencia.test.tsx Expected: PASS.

  • Step 5: Correr la suite completa y commitear

Run: pnpm test Expected: PASS.

git add components/primitives/IlustracionNudo.tsx components/primitives/IlustracionBifurcacion.tsx components/primitives/IlustracionConvergencia.tsx components/primitives/__tests__/IlustracionNudo.test.tsx components/primitives/__tests__/IlustracionBifurcacion.test.tsx components/primitives/__tests__/IlustracionConvergencia.test.tsx
git commit -m "refactor(ilustraciones): grosores unificados a la escala 1.5/2/3"

Task 4: El nudo, al centro para que el hilo lo atraviese (Dolores)

El nudo hoy vive arriba a la derecha (-top-6 right-4); el hilo central no lo toca. Se recentrea en Dolores para que el hilo (Task 1) lo atraviese —el dolor, cosido por el hilo que es lo que lo va a desatar—, conectando el nudo con el remate "se resuelve con una estrategia clara".

Files:

  • Modify: components/sections/Dolores.tsx
  • Modify: components/sections/__tests__/Dolores.test.tsx

Interfaces:

  • Consumes: IlustracionNudo (Task 3 ya dejó sus grosores listos).

  • Sin cambios de interfaz pública.

  • Step 1: Añadir el test que falla

Añadir a components/sections/__tests__/Dolores.test.tsx, dentro del describe:

  it('centres the knot so the conductor thread runs through it', () => {
    const { container } = render(<Dolores />);
    // The knot is the centred decorative svg of the section; the conductor
    // thread (Task 1) runs down the centre, so only a centred knot gets
    // traversed by it — stitching the pain to the resolution below.
    const centrados = Array.from(container.querySelectorAll('svg')).filter((s) => {
      const cls = s.getAttribute('class') ?? '';
      return cls.includes('left-1/2') && cls.includes('-translate-x-1/2');
    });
    expect(centrados.length).toBeGreaterThanOrEqual(1);
  });
  • Step 2: Correr — debe fallar

Run: pnpm test --run components/sections/__tests__/Dolores.test.tsx Expected: FAIL — el nudo está en right-4, no centrado.

  • Step 3: Recentrar el nudo en Dolores

En components/sections/Dolores.tsx, sustituir la línea del <IlustracionNudo ...> por:

      <IlustracionNudo className="pointer-events-none select-none absolute top-0 left-1/2 -translate-x-1/2 w-64 md:w-[28rem] text-azul-profundo/[0.08]" />
  • Step 4: Correr — debe pasar

Run: pnpm test --run components/sections/__tests__/Dolores.test.tsx Expected: PASS.

  • Step 5: Correr la suite completa y commitear

Run: pnpm test Expected: PASS.

git add components/sections/Dolores.tsx components/sections/__tests__/Dolores.test.tsx
git commit -m "feat(dolores): el nudo al centro para que el hilo lo atraviese"

Verificación final

  • pnpm test — todos los tests en verde
  • pnpm lint — sin warnings
  • npx tsc --noEmit — sin errores
  • pnpm build — el export estático compila
  • pnpm dev y revisar a mano:
    • (a) el hilo dorado baja visible por el centro en móvil y desktop, tras el texto (no lo cruza);
    • (b) IlustracionInflexion es una curva que se dobla, distinta del fork de ParaQuien;
    • (c) el nudo de Dolores está al centro y el hilo lo atraviesa;
    • (d) los trazos de Nudo/Bifurcación/Convergencia se ven parejos (escala 1.5/2/3).
  • Con prefers-reduced-motion: reduce: ninguna ilustración invisible, el hilo se ve estático, la página se lee completa.

Notas para quien ejecute

  • El apilado es la decisión clave del Task 1. Si en pnpm dev el hilo, estando centrado, resta legibilidad a algún título (no debería: el texto queda a z-20, sobre el hilo a z-10), no vuelvas a esconderlo en el canal: baja su opacidad (dorada/20) o reduce w-14 antes de tocar el posicionamiento. "Hilo visible al centro" es un pedido explícito de la dueña.
  • El lienzo del nudo se mantiene en 0 0 190 140. Es un ornamento de fondo que se renderiza a otra escala; forzarlo a 220×120 (como dice el spec §4) arriesga el dibujo sin aportar coherencia. La unificación de grosores (Task 3) ya cumple la intención del spec.
  • La "deriva gris punteada" de Inflexion (spec §4/§7) desaparece por diseño. El rework "sin fork" (Task 2) no tiene ruta de deriva —encarnar el punto de inflexión como una curva que se dobla, no como una bifurcación—, así que el bug del punteado no tiene dónde aplicar y se resuelve por eliminación. La única ruta punteada que queda en la página (la del "no" en ParaQuien) ya se revela por opacidad desde el plan anterior. Por eso la verificación final no lista "deriva punteada de Inflexion".
  • No reabrir las decisiones bloqueadas del AGENTS.md (paleta, wordmark, voz, "simple, directo, limpio").