uix(feature-split): una sección se nombra por su encabezado, y sus filas cuelgan de él

feature-split era el único block de sección del tier sin parte .Header. Sus
filas emitían h2 por defecto, así que una sección de tres filas aportaba tres
h2 hermanos al outline y la sección misma no tenía nombre (A-110). La página
compuesta lo rodeaba a mano: encabezado escrito como primer hijo y un level={3}
repetido fila a fila.

El h2 de las filas no era un descuido: era una decisión ESCRITA en el README
del block —«.Title emits h2 by default (each row is a section-level statement
of its own)… drop it to 3 when the page already put an h2 above the rows»—. Se
deroga en sitio, y no por gusto sino porque el resto del tier declara lo
contrario: FeatureGrid.ItemTitle, las preguntas de faq y Pricing.PlanName ponen
en level 3 lo que se repite, y el h2 lo lleva el Header.

Nace FeatureSplit.Header, calcado de Testimonials.Header (Box con medida +
Motion + Stack) y sin contexto, porque este block no tiene eje align que
heredar. Y .Title baja su default de 2 a 3. La forma queda coherente en los dos
casos, que es lo que la hace preferible a las alternativas: con .Header el h2 es
suyo y las filas cuelgan; sin .Header la app ya puso el h2 encima y las filas
cuelgan igual. La tercera vía —un contexto donde el Header marcase su presencia
y el Title derivara su nivel— daba el mismo resultado a cambio de un hijo
escribiendo en el contexto del padre, que es el patrón que ya costó un bucle de
$effect en este repo. Por un solo bit, no compensa.

Verificado en navegador, outline leído del DOM:

  /blocks/feature-split/preview   h2 «Del evento crudo a la decisión»
                                  h3 ×3 (las filas)   ← antes: h2 ×3, sin nombre
  /blocks/landing                 h2 + h3 ×2, dentro de un outline de página
                                  que ya no salta de nivel

La demo compone su encabezado y LandingSite deja de hacerlo a mano: fuera el
Stack escrito a pelo y fuera los dos level={3}. Header medido en su sitio (x
144, 768 de ancho: la misma medida que la copia de las filas).

Gates: svelte-check 72/62 antes y después · vitest src/uix/blocks 36/36 ·
blocks:check verde (19 blocks, 147 ficheros) · docs:check 0/0.

Primera fila del ledger arreglada DENTRO del tier, por acotación del eje: las
tres anteriores de la sesión (A-111, A-112, A-109) eran todas de canon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-background
dev 2 months ago
parent 1e3a67ad39
commit 48bad6c726

@ -153,7 +153,7 @@ Columna **or.** = de qué sección del documento viejo salió la fila (`C` confi
| A-107 | `Switch` (canon) | doctrina | BAJA | F2b-D | El morfo declara dos partes (`provider` + `thumb`) y ninguna es etiqueta: la etiqueta visible es hermana, no es diana de clic y sólo se ata por `aria-labelledby` | `src/uix/morfo/components/switch.ts` | CONFIRMADO |
| A-108 | `Dialog` (canon) | doctrina | MEDIA | F2b-D | Al cerrar devuelve el foco al nodo que lo tenía al abrir; si ese disparador se desmontó, acaba en el `body` — y la trampa sigue armada un frame más | `src/uix/soma/components/dialog/dialog-provider.svelte.ts` | CONFIRMADO |
| A-109 | `Banner` (canon) + `banner` | doctrina | MEDIA | F2b-D | DOS landmarks `banner` en toda página con cabecera: el canon estampa `role="banner"` DESPUÉS de los rest props, así que nombrar ambos es lo único que queda | `src/uix/eidos/components/banner/banner.svelte` | ARREGLADO |
| A-110 | `feature-split` | doctrina | MEDIA | F2b-D | Único block de sección sin parte `.Header`: sus filas emiten `h2`, así que en una página compuesta la sección no tiene nombre y aporta tres `h2` hermanos | `src/uix/blocks/feature-split/types.ts` | CONFIRMADO |
| A-110 | `feature-split` | doctrina | MEDIA | F2b-D | Único block de sección sin parte `.Header`: sus filas emiten `h2`, así que en una página compuesta la sección no tiene nombre y aporta tres `h2` hermanos | `src/uix/blocks/feature-split/types.ts` | ARREGLADO |
| A-111 | `NavigationMenu` (canon) | doctrina | ALTA | F3.1 | Su landmark `<nav>` sale ANONIMO: el `aria-label` se reenvia al `<ul>`, y un `<ul>` no es un landmark. Invisible con una sola navegacion en la pagina; en un shell hay tres | `src/uix/morfo/components/navigation-menu.ts` | ARREGLADO |
| A-112 | `Toolbar.Button` (canon) | doctrina | MEDIA | F3.1 | Tipa contra el `ButtonProps` de SOMA (`{id, disabled}`), asi que no acepta `variant`/`color`: un cluster no puede decir cual es su accion principal | `src/uix/eidos/components/toolbar/types.ts` | ARREGLADO |
| A-113 | fundacion de eidos | doctrina | ALTA | F3.1 | La foundation emite los estilos semanticos (`--style-body-*`) y no los aplica a NINGUN elemento: todo lo que el canon renderiza como texto plano hereda del documento, y ahi no habia nada — Times New Roman en los 19 previews | `web/routes/blocks/_lib/reset.css` | ARREGLADO |
@ -1944,12 +1944,39 @@ Píxel idéntico (la receta selecciona `[data-banner]`, no el elemento): tira a
sangre 1280×54 con el mismo fondo. Prosa re-sincronizada en 11 sitios (READMEs
de canon, block y app-shell, tres demos, `landing`, la ficha de auditoría).
### A-110 — CONFIRMADO · `feature-split` · doctrina · MEDIA
### A-110 — ARREGLADO · `feature-split` · doctrina · MEDIA
**Mecanismo** — es el único block de sección sin parte `.Header`: `feature-grid`, `testimonials`, `faq` y `pricing` la tienen. Sus `Row` emiten `Title` a `level={2}` por defecto, así que una sección de tres filas aporta **tres `h2` hermanos** y la sección misma no tiene nombre. Un app puede componer el encabezado a mano como primer hijo (el root renderiza `{@render children()}` dentro de un `Stack`) y bajar las filas a `level={3}` —lo que hace la página compuesta—, pero eso es reconstruir a mano lo que el resto del tier declara.
**Evidencia** — `src/uix/blocks/feature-split/types.ts` (sin `header`) · `feature-split-title.svelte:6` (`level = 2`) · el outline medido en `/blocks/landing`.
**ARREGLADO 2026-08-19.** Nace `FeatureSplit.Header` (calcado de
`Testimonials.Header`: `Box` con medida + `Motion` + `Stack`, sin contexto —
este block no tiene eje `align` que heredar) y **`.Title` baja su default de
`2` a `3`**, que es lo que declaran los cuatro hermanos del tier
(`FeatureGrid.ItemTitle`, las preguntas de `faq`, `Pricing.PlanName`).
⚠️ Con un matiz que la ficha no recogía: **el `h2` de las filas era una decisión
ESCRITA**, no un descuido — el README del block decía «`.Title` emits `h2` by
default (each row is a section-level statement of its own)… drop it to `3` when
the page already put an `h2` above the rows». Queda derogada en sitio. La forma
elegida es coherente en los dos casos: con `.Header`, el `h2` es suyo y las
filas cuelgan; sin `.Header`, la app ya puso el `h2` arriba y las filas siguen
colgando igual.
**Verificado** — outline medido en navegador:
```
/blocks/feature-split/preview h2 «Del evento crudo a la decisión»
h3 ×3 (las filas) ← antes: h2 ×3, sin nombre
/blocks/landing h2 «Del evento crudo…» + h3 ×2, dentro de un
outline de página que ya no tiene saltos
```
La página compuesta deja de componer su encabezado a mano y de pasar
`level={3}` fila a fila: `LandingSite.svelte` usa la parte. `blocks:check`
verde (19 blocks, 147 ficheros) · `vitest src/uix/blocks` 36/36.
### A-111 — ARREGLADO · `NavigationMenu` (canon) · doctrina · ALTA
**Mecanismo** — El `aria-label` que el consumidor pasa al root de

@ -67,6 +67,28 @@ Y **F3 sigue**: el orden del plan es `app-shell` (HECHO) → `error-page` →
son justo las piezas que le faltan a la barra del shell, así que hacerlas
seguidas tiene un consumidor real esperando.
### Lo que dejó la sesión de A-110 (2026-08-19)
**Primera fila arreglada DENTRO del tier** — decisión tuya de acotar el eje a
`src/uix/blocks/` + `web/routes/blocks/`, después de tres cierres seguidos que
fueron todos de canon.
`FeatureSplit` gana su `.Header` (era el único block de sección sin ella) y
`.Title` baja de `h2` a `h3`, como declaran los cuatro hermanos. ⚠️ El `h2` de
las filas **era una decisión escrita en el README**, no un descuido: queda
derogada en sitio. Medido: el preview pasa de tres `h2` hermanos sin nombre de
sección a `h2` + tres `h3`, y `/blocks/landing` deja de componer el encabezado
a mano y de bajar cada fila a `level={3}`.
**Lo que queda dentro de la frontera**, por si entras por aquí: A-11 y A-29
(demos que redeclaran tipos del canon y que construyen mal la URL del preview) ·
A-71 (el arnés pinta el block antes del `h1`) · A-96 (`affixOffset` sin control
vivo) · A-74 (anclas muertas en la demo de feature-split) · A-53 · A-62 · A-65 ·
A-75 · A-48 · A-60 · A-79 (SOSP) · A-55 (medida, pero el autor la ve centrada) ·
A-92 (sólo doc de motion). Fuera de la frontera y por tanto CONGELADAS mientras
el eje sea «sólo bloques»: A-106, A-107, A-108, A-114, A-115, A-116 (canon) y
A-09, A-47, A-67, cuya ficha sitúa el arreglo en canon.
### Lo que dejó la sesión de A-109 (2026-08-19)
**El `Banner` deja de reclamar el landmark `banner`**: `<section>` sin rol —
@ -207,7 +229,7 @@ veredictos desemparejados de sus hallazgos por un join por POSICIÓN, y el journ
del workflow era de sesión. Se reprodujo en vivo al re-verificar — el journal
devuelve los resultados en un orden distinto al de entrada.
Estado del ledger (2026-08-19): **75 ARREGLADO · 25 CONFIRMADO · 13 REFUTADO ·
Estado del ledger (2026-08-19): **76 ARREGLADO · 24 CONFIRMADO · 13 REFUTADO ·
3 DATO** (116 filas: las 90 originales + A-91…A-116). Cero
pendientes: todas están medidas. La tasa real de refutación fue del **13%**, no
del 28%.

@ -11,20 +11,28 @@ beside a screenshot, repeated down the page.
| Part | Composes | Notes |
| ------------------------ | ---------------------------------------------------- | ------------------------------------------------------------------ |
| root | bare `<section>` + `Section` + `Container` + `Stack` | stacks the rows |
| root | bare `<section>` + `Section` + `Container` + `Stack` | stacks the header and the rows |
| `.Header` | `Box` (measure-cap) + `Motion` + `Stack` | the section's name: a `Heading level={2}` and usually a `Text` |
| `.Row` | `Grid` (2-col) + `Box` (grid placement) | `reversed` flips the sides via `grid-column`; DOM stays copy-first |
| `.Row` `media` slot | — (app: a `Mockup`, `Image`, `AspectRatio`) | the media column |
| `.Eyebrow` | `Text` (primary, semibold, sm) | the small label above the title |
| `.Title` | `Heading` (level 2) | the row's claim |
| `.Title` | `Heading` (level 3) | the row's claim, under the header's h2 |
| `.Text` | `Text` (muted, lg) | the supporting sentence |
| `.Features` / `.Feature` | `Stack` / `Group` + `Icon.Check` + `Text` | the checklist; the check is decorative (aria-hidden) |
| `.Actions` | `Group` | the CTA cluster |
**Landmark + headings**: a bare `<section>` with NO accessible name of its own,
so it is not an exposed landmark — the app names it by passing `aria-label` /
`aria-labelledby` through `...rest`. `.Title` emits `h2` by default (each row is a
section-level statement of its own) and takes `level` to move it — drop it to
`3` when the page already put an `h2` above the rows.
**Landmark + headings**: a bare `<section>`, so it is an exposed landmark only
when the app names it (`aria-label` / `aria-labelledby` through `...rest`) — a
`<section>` becomes a `region` only with an accessible name. The OUTLINE is the
part's job: `.Header` carries the section's `h2` and `.Title` emits `h3`, one
level under it, as in every sibling of the tier (`FeatureGrid.ItemTitle`, the
`Faq` questions, `Pricing.PlanName`). A section composed WITHOUT a `.Header` is
saying its name lives above it in the page, and its rows still hang at `h3`.
⚠️ **Derogado 2026-08-19 (A-110)**: este párrafo decía que `.Title` emite `h2`
por defecto «porque cada fila es una afirmación de nivel de sección», y que el
app la bajara a `3` a mano. Era el único block de sección sin `.Header`, así que
una sección de tres filas aportaba tres `h2` hermanos y ningún nombre propio.
**Reversal keeps reading order**: the copy is always first in the DOM; `reversed`
only sets `grid-column` so the media moves to the inline-start side. Screen

@ -0,0 +1,26 @@
<script lang="ts">
/**
* FeatureSplit.Header — the section title + description, measure-capped. The
* app supplies a `Heading` (level 2) and a `Text`; their alignment is the
* app's to choose, as in `Testimonials.Header` (this block has no `align`
* axis of its own, so there is nothing to inherit).
*
* It exists because a section names itself through its header (A-110): this
* was the only section block of the tier without one, so a three-row section
* contributed three sibling `h2`s and no name of its own.
*/
import { Box } from '$uix/eidos/components/box';
import { Stack } from '$uix/eidos/components/stack';
import { Motion } from '$uix/eidos/components/motion';
import type { FeatureSplitHeaderProps } from './types';
let { maxWidth = '48rem', children, ...rest }: FeatureSplitHeaderProps = $props();
</script>
<Box {maxWidth} width="100%" {...rest}>
<Motion trigger="viewport">
<Stack gap={3}>
{@render children?.()}
</Stack>
</Motion>
</Box>

@ -1,9 +1,12 @@
<script lang="ts">
/** FeatureSplit.Title — the row's heading (level 2 by default). */
/**
* FeatureSplit.Title — the row's heading (level 3 by default: a statement
* inside the section, under the `Header`'s h2 — A-110).
*/
import { Heading } from '$uix/eidos/components/heading';
import type { FeatureSplitTitleProps } from './types';
let { level = 2, children, ...rest }: FeatureSplitTitleProps = $props();
let { level = 3, children, ...rest }: FeatureSplitTitleProps = $props();
</script>
<Heading {level} wrap="balance" {...rest}>

@ -6,6 +6,10 @@
// import { Mockup } from '$uix/eidos/components/mockup';
//
// <FeatureSplit>
// <FeatureSplit.Header>
// <Heading level={2}>Del evento crudo a la decisión</Heading>
// <Text color="muted">Tres pasos, ninguno tuyo.</Text>
// </FeatureSplit.Header>
// <FeatureSplit.Row>
// {#snippet media()}
// <Mockup chrome="browser" url="acme.app"><img src="…" /></Mockup>
@ -25,6 +29,7 @@
// Every visible string is the app's (B-7). The media is composed — a `Mockup`
// gives it browser / phone chrome.
import FeatureSplitComponent from './feature-split.svelte';
import Header from './feature-split-header.svelte';
import Row from './feature-split-row.svelte';
import Eyebrow from './feature-split-eyebrow.svelte';
import Title from './feature-split-title.svelte';
@ -34,6 +39,7 @@ import Feature from './feature-split-feature.svelte';
import Actions from './feature-split-actions.svelte';
type FeatureSplitNamespace = typeof FeatureSplitComponent & {
Header: typeof Header;
Row: typeof Row;
Eyebrow: typeof Eyebrow;
Title: typeof Title;
@ -44,6 +50,7 @@ type FeatureSplitNamespace = typeof FeatureSplitComponent & {
};
const FeatureSplit = FeatureSplitComponent as FeatureSplitNamespace;
FeatureSplit.Header = Header;
FeatureSplit.Row = Row;
FeatureSplit.Eyebrow = Eyebrow;
FeatureSplit.Title = Title;
@ -57,6 +64,7 @@ export default FeatureSplit;
export type {
FeatureSplitProps,
FeatureSplitHeaderProps as HeaderProps,
FeatureSplitRowProps as RowProps,
FeatureSplitEyebrowProps as EyebrowProps,
FeatureSplitTitleProps as TitleProps,

@ -1,5 +1,6 @@
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import type { BoxProps } from '$uix/eidos/components/box';
import type { ContainerSize } from '$uix/eidos/components/container';
import type { SectionSize } from '$uix/eidos/components/section';
import type { StackProps } from '$uix/eidos/components/stack';
@ -26,10 +27,16 @@ export type FeatureSplitProps = Omit<HTMLAttributes<HTMLElement>, 'children'> &
sectionSize?: SectionSize;
/** Gap between the alternating rows (space scale). @default 12 */
gap?: number;
/** The `Row`s. */
/** The optional `Header` and the `Row`s, in composition order. */
children?: Snippet;
};
/**
* Wraps a `Box` (measure-cap). `maxWidth` defaults to `48rem`. The section's
* name lives here (A-110): a `Heading level={2}` plus, usually, a `Text`.
*/
export type FeatureSplitHeaderProps = BoxProps;
/**
* A `Row` composes a `Grid`, and its `media` slot is a snippet whose name would
* collide with the HTML `media` attribute — so this is a clean type, not an
@ -50,7 +57,12 @@ export type FeatureSplitRowProps = {
/** Wraps a `Text` — the small coloured label above the title. `color` → `primary`. */
export type FeatureSplitEyebrowProps = TextProps & { color?: ComponentColorProp };
/** Wraps a `Heading`. `level` defaults to `2`. */
/**
* Wraps a `Heading`. `level` defaults to **`3`** — a row is a statement INSIDE
* the section, one level under the `Header`'s `h2`, as in every sibling of the
* tier (`FeatureGrid.ItemTitle`, `Faq` questions, `Pricing.PlanName`). It
* defaulted to `2` until A-110, when the block gained its `Header`.
*/
export type FeatureSplitTitleProps = HeadingProps;
/** Wraps a muted `Text`. */

@ -27,7 +27,7 @@
{previewSrc}
previewHeight="820px"
meta={[
{ key: 'compone', value: 'Section · Container · Grid · Mockup · Heading · Text · Icon' },
{ key: 'compone', value: 'Section · Container · Box · Grid · Mockup · Heading · Text · Icon' },
{ key: 'tipo', value: 'compound (.Row repite)' },
{ key: 'media', value: 'Mockup (browser · phone)' },
{ key: 'strings propias', value: '0' }
@ -108,8 +108,12 @@
Slot de la app: aquí un <Code>Mockup</Code> —<Code>chrome="browser"</Code> o
<Code>"phone"</Code>—, el primitivo de media del canon.
</DocRow>
<DocRow term=".Header">
<Code>Box</Code> con medida + <Code>Stack</Code>: el nombre de la sección. La app pone un
<Code>Heading level=&#123;2&#125;</Code> y, normalmente, un <Code>Text</Code>.
</DocRow>
<DocRow term=".Eyebrow · .Title · .Text">
<Code>Text</Code> primary + <Code>Heading</Code> (h2) + <Code>Text</Code> apagado. La app pone
<Code>Text</Code> primary + <Code>Heading</Code> (h3) + <Code>Text</Code> apagado. La app pone
las palabras.
</DocRow>
<DocRow term=".Features · .Feature">
@ -149,8 +153,10 @@
<Code>grid-column</Code>), así que lectores y teclado ven copy→media en toda fila.
</DocRow>
<DocRow term="Encabezados">
Cada fila un <Code>h2</Code> (ajustable por <Code>level</Code>). El check de cada feature es
decorativo (<Code>aria-hidden</Code>): la palabra lleva el significado.
El <Code>h2</Code> es del <Code>.Header</Code> y cada fila cuelga en <Code>h3</Code> (ajustable
por <Code>level</Code>), como en el resto del tier. Hasta <Code>A-110</Code> no había
<Code>.Header</Code> y tres filas emitían tres <Code>h2</Code> hermanos. El check de cada feature
es decorativo (<Code>aria-hidden</Code>): la palabra lleva el significado.
</DocRow>
<DocRow term="Media">
El <Code>Mockup</Code> es cromo decorativo; si su contenido es una imagen informativa, la app

@ -64,6 +64,15 @@
</script>
<FeatureSplit>
<!--
The section names itself (A-110): the `h2` is the header's and each row
hangs at `h3`. Before the part existed, three rows meant three sibling
`h2`s and a section with no name at all.
-->
<FeatureSplit.Header>
<Heading level={2}>Del evento crudo a la decisión</Heading>
<Text color="muted" size="lg">Tres capacidades, cada una al lado de lo que hace.</Text>
</FeatureSplit.Header>
{#each shown as row, i (row.title)}
<FeatureSplit.Row reversed={i % 2 === (startReversed ? 0 : 1)}>
{#snippet media()}

@ -487,18 +487,19 @@
</FeatureGrid>
<!--
`feature-split` is the one section block with no `.Header` part, so the
section heading is hand-composed as its first child and the rows drop to
`level={3}`. Left at their default the three rows emit three sibling `h2`
and the section has no name — recorded as a gap in this page's README.
`FeatureSplit.Header` carries the section's `h2` and the rows hang at `h3`
by default (A-110). Until 2026-08-19 this block was the one section block
with no `.Header`: the heading was hand-composed as a first child and each
row had to be dropped to `level={3}` by hand, or the section emitted three
sibling `h2` and no name of its own.
-->
<FeatureSplit>
<Stack gap={3} align="center">
<FeatureSplit.Header>
<Heading level={2} align="center">Del evento crudo a la decisión</Heading>
<Text size="lg" color="muted" align="center">
Dos piezas que trabajan sobre el mismo flujo, sin copiar datos de una a otra.
</Text>
</Stack>
</FeatureSplit.Header>
<FeatureSplit.Row>
{#snippet media()}
@ -515,7 +516,7 @@
</Mockup>
{/snippet}
<FeatureSplit.Eyebrow>Analítica</FeatureSplit.Eyebrow>
<FeatureSplit.Title level={3}>Cohortes al día, sin configurar pipelines</FeatureSplit.Title>
<FeatureSplit.Title>Cohortes al día, sin configurar pipelines</FeatureSplit.Title>
<FeatureSplit.Text>
Los eventos llegan crudos y salen en cohortes: qué hicieron, cuándo dejaron de hacerlo y qué
cambió la semana en que lanzaste.
@ -546,7 +547,7 @@
</Mockup>
{/snippet}
<FeatureSplit.Eyebrow>En el bolsillo</FeatureSplit.Eyebrow>
<FeatureSplit.Title level={3}>Las alertas que importan, donde las lees</FeatureSplit.Title>
<FeatureSplit.Title>Las alertas que importan, donde las lees</FeatureSplit.Title>
<FeatureSplit.Text>
Un umbral sobre cualquier métrica y el canal —o el móvil— donde de verdad lo ves. Sin abrir
el panel.

@ -63,7 +63,7 @@ en pasos y se captura por viewport.
| **`Newsletter.Reason` medía 2,33:1 sobre el panel** (la nota a su lado, 8,5:1) | block `newsletter` | **ARREGLADO aquí** — la razón toma la tinta del panel como el resto; 2,33 → **8,83:1**. Off-panel sigue `muted` |
| ~~**DOS landmarks `banner`**~~ | canon `Banner` | **CERRADO (A-109, 2026-08-19)** — el canon dejó de reclamar el rol: `<section>`, `region` sólo al nombrarla. La página expone UN `banner`, el de la cabecera |
| **A-95**: `affix="top"` tapa la cabecera fijada | canon `Affix` + tier | **re-confirmado** — la pieza que falta es `app-shell` (F3.1). La página compone en flujo, que es correcto |
| **`feature-split` no tiene parte `.Header`** | block `feature-split` | **gap** — es el único block de sección sin ella; aquí el encabezado va a mano como primer hijo y las filas bajan a `level={3}`. Sin eso emite tres `h2` hermanos y la sección no tiene nombre |
| ~~**`feature-split` no tiene parte `.Header`**~~ | block `feature-split` | **CERRADO (A-110, 2026-08-19)** — la parte existe: el `h2` es suyo y las filas cuelgan en `h3` por defecto. Esta página dejó de componer el encabezado a mano y de bajar cada fila |
| Un `AspectRatio` 9/16 en una columna partida da un móvil de 995px | esta página | **arreglado aquí** — la pantalla del móvil lleva alto fijo, como ya hacía la demo del propio block |
## Cómo se ve

Loading…
Cancel
Save

Powered by TurnKey Linux.