/**
 * Word Swap Heading — style.css
 *
 * Every word sits in the same grid cell, so the slot is as wide as the widest
 * word and one line tall from first paint: nothing shifts when words change.
 * Motion is transform/opacity only; view.js just moves classes.
 */

.oi-word-swap__heading {
    margin-block: 0;
}

.oi-word-swap__slot {
    display: inline-grid;
}

.oi-word-swap.is-placement-line .oi-word-swap__slot {
    display: grid;
}

.oi-word-swap__word {
    grid-area: 1 / 1;
}

/* Alternates print through ::before so the heading's text stays
   "before + first word + after" for search engines and copy/paste. */
.oi-word-swap__word[data-oi-word]::before {
    content: attr(data-oi-word);
}

/* ── Roll ─────────────────────────────────────────────────────────────────
   Words wait just outside a clipped line and slide through it. The clip
   reaches a little past the line box so descenders and italics aren't cut;
   parked words sit past the clip. */

.oi-word-swap.is-effect-roll {
    --oi-ws-park: calc(100% + 0.3em);
}

.oi-word-swap.is-effect-roll.is-dir-down {
    --oi-ws-park: calc(-100% - 0.3em);
}

.oi-word-swap.is-effect-roll .oi-word-swap__slot {
    clip-path: inset(-0.2em -0.15em);
}

.oi-word-swap.is-effect-roll .oi-word-swap__word {
    transform: translateY(var(--oi-ws-park));
    transition: transform var(--oi-ws-speed, 0.7s) cubic-bezier(0.65, 0, 0.35, 1);
}

.oi-word-swap.is-effect-roll .oi-word-swap__word.is-current {
    transform: none;
}

.oi-word-swap.is-effect-roll .oi-word-swap__word.is-above {
    transform: translateY(calc(-100% - 0.3em));
}

.oi-word-swap.is-effect-roll .oi-word-swap__word.is-below {
    transform: translateY(calc(100% + 0.3em));
}

/* ── Fade ─────────────────────────────────────────────────────────────────
   Out, then in — the two words never overlap on screen. */

.oi-word-swap.is-effect-fade .oi-word-swap__word {
    opacity: 0;
    transition: opacity calc(var(--oi-ws-speed, 0.7s) / 2) ease;
}

.oi-word-swap.is-effect-fade .oi-word-swap__word.is-current {
    opacity: 1;
    transition-delay: calc(var(--oi-ws-speed, 0.7s) / 2);
}

/* Moves a word to its entry side without animating it. */
.oi-word-swap .oi-word-swap__slot .oi-word-swap__word.is-snap {
    transition: none;
}

/* ── Pause button ─────────────────────────────────────────────────────────
   Rendered hidden (space reserved, so revealing it doesn't shift the page);
   view.js adds .is-running once the animation starts. */

.oi-word-swap__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    margin-block-start: var(--wp--preset--spacing--20, 0.5rem);
    padding: 0;
    border: 1px solid currentColor;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
    visibility: hidden;
}

.oi-word-swap.has-text-align-center > .oi-word-swap__toggle {
    margin-inline: auto;
}

.oi-word-swap.has-text-align-right > .oi-word-swap__toggle {
    margin-inline-start: auto;
}

.oi-word-swap.is-running > .oi-word-swap__toggle {
    visibility: visible;
}

/* Corner: absolute from first paint, so it never takes space in the flow.
   view.js then moves it into the surrounding cover/section (.oi-word-swap-host)
   — a cover's inner container is position:relative, so CSS alone would pin it
   to the content block instead of the section's bottom — and sets
   --oi-ws-toggle-end so its edge lines up with the heading's content column.
   z-index clears the cover's image (0) and overlay (1). */
.oi-word-swap.is-toggle-corner > .oi-word-swap__toggle,
.oi-word-swap-host > .oi-word-swap__toggle {
    position: absolute;
    inset-inline-end: calc(var(--oi-ws-toggle-end, var(--wp--preset--spacing--40, 1.5rem)) + var(--oi-ws-toggle-offset, 0) * 2.75rem);
    bottom: var(--wp--preset--spacing--40, 1.5rem);
    z-index: 2;
    margin: 0;
}

.oi-word-swap-host > .oi-word-swap__toggle {
    visibility: visible;
}

.oi-word-swap-host--relative {
    position: relative;
}

.oi-word-swap__toggle:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 2px;
}

.oi-word-swap__icon {
    display: block;
    width: 0.75rem;
    height: 0.75rem;
}

/* State lives on the button itself — in corner mode it's no longer inside the block. */
.oi-word-swap__icon--play,
.oi-word-swap__toggle.is-paused .oi-word-swap__icon--pause {
    display: none;
}

.oi-word-swap__toggle.is-paused .oi-word-swap__icon--play {
    display: block;
}

/* Reduced motion: view.js never starts, so the first word stays put and the
   button has nothing to control. */
@media (prefers-reduced-motion: reduce) {
    .oi-word-swap__toggle {
        display: none;
    }
}

/* The page has the site's Pause Animations link (blocks/motion-toggle/), which
   covers WCAG 2.2.2 for the whole page. The class is set in <head>, so the
   button never shows or takes space. */
html.oi-has-motion-toggle .oi-word-swap__toggle {
    display: none;
}
