/* ── Content (variant-shared base) ──────────────────────────────────────── */ [data-floating-wrapper]:has(> [data-tooltip-content]) { z-index: var(--tooltip-content-z); } [data-tooltip-content] { --_tooltip-padding-block: var(--tooltip-padding-block-md); --_tooltip-padding-inline: var(--tooltip-padding-inline-md); --_tooltip-font-size: var(--tooltip-font-size-md); --_tooltip-bg: var(--tooltip-bg); --_tooltip-border: var(--tooltip-border); --_tooltip-shadow: var(--tooltip-shadow); /* private: per-instance VALUE CHANNEL — `--_tooltip-content-width-override` and `--_tooltip-match-anchor-width` are written per instance and nobody declares them; `auto` is the identity when neither is set. A theme pinning one would break `matchAnchorWidth`. Same class `drawer` §5 signed. */ --_tooltip-width: var(--_tooltip-content-width-override, var(--_tooltip-match-anchor-width, auto)); --_tooltip-max-width: var(--_tooltip-content-max-width-override, var(--tooltip-max-width)); --_tooltip-max-height: var( --_tooltip-content-max-height-override, var(--floating-available-height, calc(100dvh - var(--space-4))) ); display: block; box-sizing: border-box; inline-size: var(--_tooltip-width); min-inline-size: var(--_tooltip-content-min-width-override, auto); max-inline-size: min(var(--_tooltip-max-width), calc(100vw - var(--space-4))); block-size: var(--_tooltip-content-height-override, auto); min-block-size: var(--_tooltip-content-min-height-override, auto); max-block-size: var(--_tooltip-max-height); padding-block: var(--_tooltip-padding-block); padding-inline: var(--_tooltip-padding-inline); /* `visible` so the absolutely-positioned caret (containing block = this relative * content) is NOT clipped where it pokes past the panel edge — the same reason * the popover content is `overflow: visible`. Without this the arrow was clipped * away entirely. Tooltips are short, so no inner scroll viewport is needed. */ overflow: visible; border: var(--tooltip-border-width) solid var(--_tooltip-border); border-radius: var(--tooltip-radius); background: var(--_tooltip-bg); color: var(--tooltip-fg); box-shadow: var(--_tooltip-shadow); transform-origin: var(--floating-transform-origin, center); font-family: var(--tooltip-font-family); font-size: var(--_tooltip-font-size); font-weight: var(--tooltip-font-weight); line-height: var(--tooltip-line-height); text-wrap: pretty; } /* ── Sizes ──────────────────────────────────────────────────────────────── */ [data-tooltip-content][data-size='sm'] { --_tooltip-padding-block: var(--tooltip-padding-block-sm); --_tooltip-padding-inline: var(--tooltip-padding-inline-sm); --_tooltip-font-size: var(--tooltip-font-size-sm); } [data-tooltip-content][data-size='lg'] { --_tooltip-padding-block: var(--tooltip-padding-block-lg); --_tooltip-padding-inline: var(--tooltip-padding-inline-lg); --_tooltip-font-size: var(--tooltip-font-size-lg); } /* ── Variants ───────────────────────────────────────────────────────────── */ /* `solid` is the default surface — the base block already paints it. */ [data-tooltip-content][data-variant='outline'] { --_tooltip-bg: transparent; /* literal: the outline variant IS transparent — identity, not a knob */ --_tooltip-border: var(--color-border-strong); --_tooltip-shadow: none; /* literal: this variant IS shadowless — identity, not a knob */ } [data-tooltip-content][data-variant='ghost'] { /* El plano `overlay` pinta la superficie y gana a esta declaración: se deja con su valor literal porque acuñar un token aquí sería acuñar una mentira (medido 2026-08-23; §12.9). */ --_tooltip-bg: color-mix(in srgb, var(--color-surface-overlay) 70%, transparent); --_tooltip-border: transparent; --_tooltip-shadow: none; /* literal: this variant IS shadowless — identity, not a knob */ backdrop-filter: blur(var(--tooltip-ghost-blur)); } /* ── Arrow ──────────────────────────────────────────────────────────────── */ /* `display: block` keeps the SVG off the text baseline — inline added ~21px of * phantom height that both misaligned the caret AND pushed the panel too far from * the trigger (the positioner adds the measured arrow height to the gap). */ [data-tooltip-arrow] svg { display: block; overflow: visible; } /* Colour the SVG shapes directly — the polygon/path carry `fill`/`stroke = * "currentColor"` presentation attributes that a `fill`/`stroke` on the wrapping * can't override. The body matches the panel bg (a seamless caret, not a * dark blob) and the two exposed edges take the panel border. Now that the content * is `overflow: visible` (the caret is no longer clipped), that border outline is * what makes the matched caret read against the page — same as the popover. */ [data-tooltip-arrow] polygon { fill: var(--_tooltip-bg, var(--tooltip-bg)); stroke: none; } [data-tooltip-arrow] path { stroke: var(--_tooltip-border, var(--tooltip-border)); stroke-width: var(--tooltip-border-width); vector-effect: non-scaling-stroke; } /* Pull the caret base into the panel by the border width (per side) so the fill * covers the panel's border there and the side strokes continue the outline — * otherwise the panel border draws a line across the caret base. Mirrors the * popover recipe. */ [data-tooltip-arrow][data-side='bottom'] { margin-block-start: var(--tooltip-border-width); } [data-tooltip-arrow][data-side='top'] { margin-block-end: var(--tooltip-border-width); } [data-tooltip-arrow][data-side='left'] { margin-inline-end: var(--tooltip-border-width); } [data-tooltip-arrow][data-side='right'] { margin-inline-start: var(--tooltip-border-width); } /* Outline variant: transparent bg → fill with the surface, stroke the edges. */ [data-tooltip-content][data-variant='outline'] ~ [data-tooltip-arrow] polygon, [data-tooltip-content][data-variant='outline'] [data-tooltip-arrow] polygon { fill: var(--tooltip-outline-arrow-bg); } [data-tooltip-content][data-variant='outline'] ~ [data-tooltip-arrow] path, [data-tooltip-content][data-variant='outline'] [data-tooltip-arrow] path { stroke: var(--tooltip-outline-arrow-border); } /* ── Entrance / exit ───────────────────────────────────────────────────────── * Tooltip morfo's data-state values: 'closed' | 'delayed-open' | 'instant-open'. * The panel runs the canonical `scale-fade` preset (its original look: subtle * scale from the floating transform-origin + fade), stamped by the wrapper as * `data-animation-style`. The generator's open-state ALIAS (`delayed-open` ≡ * open — PRESET_STATE_ALIASES, render-css.ts) is what lets the tri-state * machine drive the preset; `instant-open` is deliberately NOT an alias, so a * keyboard-focus open appears with no entrance (its semantics). The recipe * keeps its tuned durations via the preset's per-element hooks. Reduced motion * is the preset's policy (`opacity-only` → quick fade). */ [data-tooltip-content] { --motion-duration-enter: var(--duration-normal); --motion-duration-exit: var(--duration-fast); } /* instant-open: no entrance — element appears at final position. */ [data-tooltip-content][data-state='instant-open'] { opacity: 1; /* literal: an open tooltip is fully visible — identity, not a knob */ transform: none; } /* The emerge firma must not add the entrance this state deliberately lacks. * On the delayed path the preset entrance wins the cascade over the global * `present-rise` signature (measured 2026-08-13); on instant-open there is no * state-keyed animation competing, so the signature would animate a focus / * skip-delay appearance — against its semantics. Visual silence, scoped to * exactly that path: the same doctrine the sema pack signs for sound * («una señal … sabe cuándo permanecer mínima o incluso silenciosa»). */ [data-tooltip-content][data-state='instant-open'][data-event-phase='active'] { animation: none; } /* ── Trigger states ───────────────────────────────────────────────────────── * Trigger is the wrapper around any focusable element (button, link, …). * The audit (R-1.2 / R-1.5) requires the recipe to acknowledge `data-disabled` * and `:focus-visible`. The wrapped element keeps its own styling; the rules * here suppress the tooltip behavior cleanly when the trigger is disabled. */ [data-tooltip-trigger][data-disabled] { pointer-events: none; cursor: not-allowed; } [data-tooltip-trigger]:focus-visible { /* Defer the focus ring to the wrapped element — but ensure the outline is at least visible if the trigger is rendered as a focusable shell. */ outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } /* Reduced motion is owned by the preset's policy (`scale-fade` → opacity-only: * a brief fade, transforms dropped) — emitted by the generator under both * `[data-motion='reduce']` and the media query. No local override needed. */