fix(forma): graceful `full` magnitude — no broken pill-in-pill

At `full` (--radius-full = 9999px) the border-radius caps to half each
element's shorter dimension. A tall card and its 16:10 cover cap to
different values, so they can never be concentric — the nest inset broke
("el borde interior no sigue el radio exterior").

Concentric nesting requires FINITE radii; `full` is for leaf elements
(chips, buttons, avatars, pill inputs). So at `full` the demo now:
- gates `[data-shape-nest]` off and dims the "radios concéntricos" toggle
  with «n/a a full — geometría de hoja»
- drops the cover to a clean --radius-xl (.cover-full) instead of a
  mismatched pill

Documented the finite-only constraint in SHAPE_ENGINE_RFC §5 + THEMING §30.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
active-uix
dev 4 months ago
parent bef15b1cd6
commit c3985a848e

@ -101,6 +101,14 @@ nada → cero rotura):
- **Anidado**: `border-radius: max(0px, calc(var(--_outer-radius) - var(--shape-nest-gap)))` —
convención en `calc()`, sin token de salida nuevo.
> **El anidado concéntrico requiere radios FINITOS.** A `full` (`--radius-full` = 9999px) el radio
> se **recorta a la mitad de la dimensión menor de cada elemento** — un contenedor alto y su hijo
> ancho (p. ej. 16:10) recortan a valores distintos, así que **no pueden ser concéntricos**. `full`
> es para **hojas** (chips · botones · avatares · inputs-píldora), no para contenedores con hijos
> que deban encajar. La regla `[data-shape-nest]` se desactiva ahí; el hijo se queda en un radio
> finito limpio. El demo `/temas/forma` lo refleja: al elegir `full`, el toggle "radios
> concéntricos" se inhabilita («n/a a full — geometría de hoja») y la carátula cae a `--radius-xl`.
## 6. Fases (la flexibilidad va horneada en cada una)
1. ✅ **Continuidad + escala + familias** — `--shape-smoothing` + `data-shape` →

@ -2322,7 +2322,10 @@ arco + estático; la continuidad solo existía en Apple, atada a plataforma).
`corner-shape` (Chromium 2025+).
- **Armonía anidada** — `[data-shape-nest]` deriva `border-radius: max(0px,
var(--shape-outer-radius) − var(--shape-nest-gap))`: el hijo queda concéntrico al padre (que
expone su radio en `--shape-outer-radius`).
expone su radio en `--shape-outer-radius`). **Requiere radios finitos**: a `full` (9999px) el
radio se recorta a la mitad de la dimensión menor *de cada elemento*, así que padre e hijo con
proporciones distintas no pueden ser concéntricos — `full` es para **hojas** (chips · botones ·
avatares · inputs-píldora), no para contenedores anidados.
- **Eventful (dos momentos)** — la forma en reposo (`data-shape`) + el **morph** al pulsar: la
firma `press-squeeze` cuadra la esquina un instante (`--shape-smoothing` 2→3→2, registrado con
`@property` para que interpole). Cross-modal: un evento mueve escala + sombra + esquina.

@ -40,6 +40,11 @@
let nest = $state(true)
let playing = $state(true)
// `full` (pill/circle) is dimension-capped per element → concentric nesting is impossible there:
// a tall pill can't have a concentric wide-pill child (their radii cap to different values).
// Concentric needs FINITE radii; `full` is for leaf elements (chips · buttons · avatars).
const isFull = $derived(radius === 'full');
const RADII = ['sm', 'md', 'lg', 'xl', 'full'] as const
// ── 4 · eventful press ───────────────────────────────────────────────────────
@ -90,8 +95,9 @@
<div
class="player-cover"
data-shape={family}
data-shape-nest={nest ? '' : undefined}
class:cover-naive={!nest}
data-shape-nest={nest && !isFull ? '' : undefined}
class:cover-naive={!nest && !isFull}
class:cover-full={isFull}
>
<button class="player-play" data-shape={family} onclick={() => (playing = !playing)}>
{playing ? '❚❚' : '▶'}
@ -143,9 +149,15 @@
</div>
</div>
<label class="ctl ctl-check">
<input type="checkbox" bind:checked={nest} />
<span class="ctl-label">radios concéntricos {nest ? '' : '· off (la carátula desencaja)'}</span>
<label class="ctl ctl-check" class:ctl-dim={isFull}>
<input type="checkbox" bind:checked={nest} disabled={isFull} />
<span class="ctl-label"
>radios concéntricos {isFull
? '· n/a a full (geometría de hoja)'
: nest
? ''
: '· off (la carátula desencaja)'}</span
>
</label>
<code class="panel-code"
@ -326,8 +338,8 @@
position: relative;
aspect-ratio: 16 / 10;
margin: var(--space-2);
/* radius comes from [data-shape-nest] (concentric) or .cover-naive — never set here, or the
scoped rule would beat the foundation's nest rule and the inset would stop being concentric */
/* radius comes from [data-shape-nest] (concentric), .cover-naive, or .cover-full — never set
here, or the scoped rule would beat the foundation's nest rule and break the concentric inset */
background:
radial-gradient(60% 80% at 30% 20%, color-mix(in oklab, var(--color-primary-solid) 90%, white), transparent 70%),
radial-gradient(70% 90% at 80% 90%, #12a594, transparent 70%),
@ -337,6 +349,10 @@
overflow: hidden;
}
.cover-naive { border-radius: var(--radius-xl); }
/* at `full` the card is a pill (radius caps to half its width); a 16:10 cover would cap to half
its HEIGHT → a horizontal pill that can't be concentric with a vertical-pill parent. Concentric
needs finite radii. So at full the cover stays cleanly rounded (a leaf), never "pill-in-pill". */
.cover-full { border-radius: var(--radius-xl); }
.player-play {
inline-size: 3.25rem;
aspect-ratio: 1;

Loading…
Cancel
Save

Powered by TurnKey Linux.