Spaces:
Running
Running
Download assets/motion/motion.css from landtml/rag-verifier: direct link, hf CLI and curl.
- Browser
- Download file 25.7 kB
-
https://huggingface.co/spaces/landtml/rag-verifier/resolve/main/assets/motion/motion.css
- Command line
-
hf download hf://spaces/landtml/rag-verifier/assets/motion/motion.css
-
curl -L -o motion.css https://huggingface.co/spaces/landtml/rag-verifier/resolve/main/assets/motion/motion.css
25.7 kB
| /* | |
| taste-skill motion.css - the micro-interactions a company site has (figma.com, x.ai): one small | |
| opt-in layer over system.css and ui/cards.css. Link it after them (data-motion on <html> is optional); | |
| load motion.js once (it adds the tab indicator, the number tick and the card loops). | |
| The layer is ON as soon as this file is linked: no attribute is needed (a hover shot of a linked card or photo | |
| shows the 2px lift and the 1.03 zoom). <html data-motion="off"> switches the whole layer off; data-motion="live" | |
| is the number tick in a headless shot (motion.js). | |
| references/motion.md says what moves and how fast. Everything here answers the pointer, the | |
| keyboard or a number coming into view once, plus the hero's one entrance on load (the end of this | |
| file); nothing moves because the page scrolled (that is a dealt moment's job, assets/moments). | |
| Hover moves sit under (hover: hover) and (pointer: fine): a phone never keeps a stuck hover. | |
| Hover out runs 120ms against 150ms in (motion.md, tokens). | |
| Under prefers-reduced-motion colours still change and a press still shows; nothing moves or scales. | |
| */ | |
| :root { | |
| --m-in: 150ms; /* hover in: buttons, links, nav, tabs */ | |
| --m-out: 120ms; /* hover out */ | |
| --m-press: 90ms; /* a press */ | |
| --m-panel: 200ms; /* a menu or sheet opening */ | |
| --m-close: 120ms; /* a menu closing */ | |
| --m-slide: 240ms; /* an indicator travelling between two tabs or links */ | |
| --m-image: 600ms; /* a photograph scaling inside its mask */ | |
| --m-image-out: 400ms; /* ...and settling back */ | |
| --m-ease: var(--ease, cubic-bezier(.2, .8, .2, 1)); /* the one UI ease-out (system.css --ease): fast start, soft landing */ | |
| --m-ease-io: cubic-bezier(.65, 0, .35, 1); /* the indicator: leaves and lands softly */ | |
| --m-ease-enter: cubic-bezier(.22, 1, .36, 1); /* an entrance settling: long soft tail, never past its mark */ | |
| --m-cycle: 3.2s; /* one cycle of a card's loop (2.5-4 s) */ | |
| --m-lift: -2px; | |
| } | |
| /* ---------------------------------------------------------------- buttons */ | |
| html:not([data-motion="off"]) .btn { | |
| position: relative; | |
| transition: background-color var(--m-out) var(--m-ease), color var(--m-out) var(--m-ease), | |
| border-color var(--m-out) var(--m-ease), box-shadow var(--m-out) var(--m-ease), | |
| transform var(--m-press) var(--m-ease); | |
| } | |
| /* the tone moves toward the ground: a black button greys a little on white, a white one on black */ | |
| html:not([data-motion="off"]) .btn--primary:hover { background: color-mix(in oklab, var(--action) 84%, var(--bg)); } | |
| html:not([data-motion="off"]) .btn--secondary:hover { | |
| background: color-mix(in oklab, var(--bg) 92%, var(--ink)); | |
| border-color: color-mix(in oklab, var(--ink) 32%, transparent); | |
| } | |
| html:not([data-motion="off"]) .btn:hover { transition-duration: var(--m-in), var(--m-in), var(--m-in), var(--m-in), var(--m-press); } | |
| html:not([data-motion="off"]) .btn:active { transform: translateY(1px) scale(.985); } | |
| /* the step: a button rises 1px on hover (2px on the large size) and presses 1px down with a 1.5% shrink on | |
| click; pointer only. The text-link secondary (arrow and block looks) keeps its underline and does not step. | |
| Reduced motion keeps the colour change only (see the end of this file). */ | |
| @media (hover: hover) and (pointer: fine) { | |
| html:not([data-motion="off"]) .btn:hover { transform: translateY(-1px); } | |
| html:not([data-motion="off"]) .btn--xl:hover { transform: translateY(-2px); } | |
| html:not([data-motion="off"]):is([data-buttons="arrow"], [data-buttons="block"]) .btn--secondary:hover { transform: none; } | |
| html:not([data-motion="off"]) .btn:active { transform: translateY(1px) scale(.985); } | |
| html:not([data-motion="off"]):is([data-buttons="arrow"], [data-buttons="block"]) .btn--secondary:active { transform: scale(.985); } | |
| } | |
| /* the arrow: the text arrow (.btn--arrow, .link) nudges 3px; the drawn arrow (.m-arrow) grows its | |
| stem and moves its head 3px, the way a good product site's "Learn more" does. The pointer's move | |
| only for a fine pointer; keyboard focus shows it anywhere */ | |
| html:not([data-motion="off"]) :is(.btn--arrow, .link)::after { transition: transform var(--m-out) var(--m-ease); } | |
| html:not([data-motion="off"]) :is(.btn--arrow, .link):focus-visible::after { transform: translateX(3px); transition-duration: var(--m-in); } | |
| .m-arrow { width: 12px; height: 12px; flex: none; overflow: visible; fill: none; stroke: currentColor; stroke-width: 1.6; | |
| stroke-linecap: round; stroke-linejoin: round; } | |
| .m-arrow__stem { opacity: 0; transform: scaleX(.2); transform-origin: 1px 50%; transform-box: fill-box; | |
| transition: opacity var(--m-out) var(--m-ease), transform var(--m-out) var(--m-ease); } | |
| .m-arrow__head { transition: transform var(--m-out) var(--m-ease); } | |
| :is(a, button):focus-visible > .m-arrow .m-arrow__stem { opacity: 1; transform: none; transition-duration: var(--m-in); } | |
| :is(a, button):focus-visible > .m-arrow .m-arrow__head { transform: translateX(3px); transition-duration: var(--m-in); } | |
| @media (hover: hover) and (pointer: fine) { | |
| html:not([data-motion="off"]) :is(.btn--arrow, .link):hover::after { transform: translateX(3px); transition-duration: var(--m-in); } | |
| :is(a, button):hover > .m-arrow .m-arrow__stem { opacity: 1; transform: none; transition-duration: var(--m-in); } | |
| :is(a, button):hover > .m-arrow .m-arrow__head { transform: translateX(3px); transition-duration: var(--m-in); } | |
| } | |
| /* a pill that is a link (the line above a hero headline) */ | |
| html:not([data-motion="off"]) a.pill { transition: background-color var(--m-out) var(--m-ease), border-color var(--m-out) var(--m-ease); } | |
| html:not([data-motion="off"]) a.pill:hover { background: color-mix(in oklab, var(--card) 90%, var(--ink)); border-color: var(--line-strong); transition-duration: var(--m-in); } | |
| /* ---------------------------------------------------------------- links: an underline that draws */ | |
| /* .link and links in running text: a rest line, and the ink line draws left to right on hover and | |
| leaves to the right. A link in a sentence rests on its own colour at 45% (about 3.3:1 on its | |
| ground), so it reads as a link even when it is the same colour as the text (WCAG 1.4.1); .link | |
| and .m-link carry an arrow or sit alone and rest on the faint hairline */ | |
| html:not([data-motion="off"]) :is(.link, .m-link, p a:not([class]), .footer ul a, .footer .link) { | |
| text-decoration: none; | |
| background-image: linear-gradient(currentColor, currentColor), linear-gradient(var(--m-rest, var(--line-strong)), var(--m-rest, var(--line-strong))); | |
| background-repeat: no-repeat; background-size: 0% 1px, 100% 1px; | |
| background-position: right 0 bottom 0, 0 100%; | |
| transition: background-size var(--m-out) var(--m-ease), color var(--m-out) var(--m-ease); | |
| padding-bottom: 2px; | |
| } | |
| /* set on its own rule: the shared rule above is (0,3,1) through :is(.footer .link) and would win */ | |
| html:not([data-motion="off"]) p a:not([class]) { --m-rest: color-mix(in oklab, currentColor 45%, transparent); } | |
| html:not([data-motion="off"]) :is(.footer ul a, .m-link--bare):not(:hover, :focus-visible) { background-size: 0% 1px, 0% 1px; } | |
| html:not([data-motion="off"]) :is(.link, .m-link, p a:not([class]), .footer ul a, .footer .link):is(:hover, :focus-visible) { | |
| background-size: 100% 1px, 100% 1px; background-position: left 0 bottom 0, 0 100%; transition-duration: var(--m-in); | |
| } | |
| /* the link's arrow is not underlined: the line runs under the words only */ | |
| html:not([data-motion="off"]) .link { background-size: 0% 1px, calc(100% - 1em - var(--s-2)) 1px; } | |
| html:not([data-motion="off"]) .link:is(:hover, :focus-visible) { background-size: calc(100% - 1em - var(--s-2)) 1px, calc(100% - 1em - var(--s-2)) 1px; } | |
| html:not([data-motion="off"]) .link, html:not([data-motion="off"]) .link:is(:hover, :focus-visible) { background-position: 0 100%, 0 100%; } | |
| html:not([data-motion="off"]) .footer ul a:hover { color: var(--ink); } | |
| /* ---------------------------------------------------------------- navigation */ | |
| /* the nav words take no pill (ST-08, ST-11): system.css draws the underline under a word from the left on hover and focus, and | |
| takes it away to the right; the page you are on keeps its still bar (system.css draws it, at the same inset) */ | |
| @media (min-width: 1024px) { | |
| /* the full-width panel: fades and settles 6px in 200ms with its columns together (one surface, read | |
| as one); it closes in 120ms. While one menu is open, the next word swaps the panel at once | |
| (motion.js .m-menu-open) */ | |
| html:not([data-motion="off"]) .nav__menu { | |
| transform: translateY(-6px); | |
| transition: opacity var(--m-close) var(--m-ease), transform var(--m-close) var(--m-ease), visibility 0s linear var(--m-close); | |
| } | |
| html:not([data-motion="off"]) .nav__item:is(:hover, :focus-within) > .nav__menu { | |
| transition: opacity var(--m-panel) var(--m-ease) 150ms, transform var(--m-panel) var(--m-ease) 150ms, visibility 0s linear 150ms; | |
| } | |
| /* .m-menu-open comes on when the first panel starts to show (150ms): from then the next word swaps | |
| the panel at once. Duration and delay go to 0, the properties stay listed, so the panel that is | |
| still fading in finishes its own 200ms instead of snapping */ | |
| html:not([data-motion="off"]) .nav.m-menu-open .nav__menu, | |
| html:not([data-motion="off"]) .nav.m-menu-open .nav__item:is(:hover, :focus-within) > .nav__menu { transition-duration: 0s; transition-delay: 0s; } | |
| html:not([data-motion="off"]) .menu-col a { transition: color var(--m-out) var(--m-ease); } | |
| html:not([data-motion="off"]) .menu-col a:hover { transition-duration: var(--m-in); } | |
| html:not([data-motion="off"]) .menu-card .panel { transition: border-color var(--m-out) var(--m-ease); } | |
| } | |
| /* the phone sheet slides in 8px and fades (system.js opens it) */ | |
| @media (max-width: 1023px) { | |
| html:not([data-motion="off"]) .nav.is-open .nav__links { transition: opacity var(--m-panel) var(--m-ease), transform var(--m-panel) var(--m-ease); } | |
| @starting-style { html:not([data-motion="off"]) .nav.is-open .nav__links { opacity: 0; transform: translateY(-8px); } } | |
| } | |
| /* ---------------------------------------------------------------- tabs: the indicator slides */ | |
| html:not([data-motion="off"]) .tabs.m-has-ind { position: relative; isolation: isolate; } | |
| html:not([data-motion="off"]) .tabs.m-has-ind .tab { position: relative; z-index: 1; } | |
| html:not([data-motion="off"]) .tabs.m-has-ind .tab[aria-selected="true"] { background: transparent; border-color: transparent; } | |
| /* the pill takes its new size at once and travels by transform alone (motion.js: it starts scaled to | |
| the old tab's size at the old place and settles to scale 1 at the new one), so nothing is laid out | |
| again while it moves and its corners are true at rest */ | |
| .m-tab-ind { | |
| position: absolute; left: 0; top: 0; z-index: 0; width: var(--w, 0px); height: var(--h, 0px); | |
| border-radius: var(--r-btn); background: var(--ink); pointer-events: none; | |
| transform: translate(var(--x, 0px), var(--y, 0px)) scale(var(--sx, 1), var(--sy, 1)); transform-origin: 0 0; | |
| transition: transform var(--m-slide) var(--m-ease-io); | |
| } | |
| .m-tab-ind.is-jump { transition: none; } | |
| html:not([data-motion="off"]) .tab { transition: color var(--m-slide) var(--m-ease), border-color var(--m-out) var(--m-ease), background-color var(--m-out) var(--m-ease); } | |
| /* ---------------------------------------------------------------- focus */ | |
| /* the ring (system.css) is drawn in full in the frame the focus lands; no transition */ | |
| /* ---------------------------------------------------------------- cards: a 2px lift */ | |
| /* the card rises 2px, its border and shadow deepen; a card without its own box (.card--open) lifts | |
| its panel. Never tilts, flips or follows the pointer */ | |
| html:not([data-motion="off"]) .card:not(.card--open, .card--plan) { | |
| transition: transform var(--m-out) var(--m-ease), border-color var(--m-out) var(--m-ease), box-shadow var(--m-out) var(--m-ease); | |
| } | |
| html:not([data-motion="off"]) .card--open > .panel { transition: transform var(--m-out) var(--m-ease), box-shadow var(--m-out) var(--m-ease); } | |
| @media (hover: hover) and (pointer: fine) { | |
| html:not([data-motion="off"]) .card:not(.card--open, .card--plan, .m-nolift):hover { | |
| transform: translateY(var(--m-lift)); | |
| border-color: color-mix(in oklab, var(--ink) 16%, transparent); | |
| /* the shadow is deeper on a dark card (its lightness l): about .2 on white, .64 on near-black */ | |
| box-shadow: inset 0 1px 0 var(--c-hi, transparent), 0 1px 2px rgb(0 0 0 / .06), | |
| 0 14px 32px -18px oklch(from var(--card, #fff) 0 0 0 / calc(0.75 - l * 0.55)); | |
| transition-duration: 180ms; | |
| } | |
| html:not([data-motion="off"]) .card--open:not(.m-nolift):hover > .panel { | |
| transform: translateY(var(--m-lift)); box-shadow: 0 14px 32px -18px oklch(from var(--bg, #fff) 0 0 0 / calc(0.75 - l * 0.55)); transition-duration: 180ms; | |
| } | |
| } | |
| /* ---------------------------------------------------------------- photographs: 1.03 inside the mask */ | |
| /* a photograph in a link or a linked card grows 3% inside its own mask (the frame, the tile, a .m-zoom wrapper); | |
| the mask clips it, so the box never moves. .m-zoom is the hook for any other photograph: wrap it. */ | |
| .m-zoom { overflow: clip; } | |
| html:not([data-motion="off"]) :is(.frame__img, .tile__media > img, .m-zoom img, .m-zoom > video) { | |
| transition: transform var(--m-image-out) var(--m-ease); | |
| } | |
| @media (hover: hover) and (pointer: fine) { | |
| html:not([data-motion="off"]) :is(a, .card:has(a), .m-zoom):hover :is(.frame__img, .tile__media > img), | |
| html:not([data-motion="off"]) .m-zoom:hover :is(img, video) { transform: scale(1.03); transition-duration: var(--m-image); } | |
| } | |
| /* ---------------------------------------------------------------- inputs, switches, checks */ | |
| html:not([data-motion="off"]) .field :is(input, select, textarea), .m-input { | |
| transition: border-color var(--m-out) var(--m-ease), box-shadow var(--m-out) var(--m-ease), background-color var(--m-out) var(--m-ease); | |
| } | |
| html:not([data-motion="off"]) .field :is(input, select, textarea):hover, .m-input:hover { border-color: color-mix(in oklab, var(--ink) 48%, transparent); } | |
| html:not([data-motion="off"]) .field :is(input, select, textarea):focus, .m-input:focus { | |
| /* the field's own ring in place of the outline: a 2px line in --action (3:1 on the ground) and a soft halo, | |
| there at once like every focus ring (the hover's fade does not apply to focus) */ | |
| outline: none; border-color: var(--action); | |
| box-shadow: 0 0 0 1px var(--action), 0 0 0 4px color-mix(in oklab, var(--action) 20%, transparent); transition-duration: 0s; | |
| } | |
| /* a switch: <button class="m-switch" role="switch" aria-checked="false" aria-label="..."></button> | |
| (motion.js flips aria-checked on click unless the page handles it). The knob slides in 180ms and | |
| stretches 4px while pressed, both by transform (a scaleX from its left edge; on, the 12px shift | |
| keeps its right edge where it rests). The off track is ink at 48% (3.3:1 or more against the knob | |
| and the ground, the 3:1 a control needs) */ | |
| .m-switch { | |
| position: relative; flex: none; width: 40px; height: 24px; padding: 0; border: 0; border-radius: 999px; cursor: pointer; | |
| background: color-mix(in oklab, var(--ink) 48%, var(--bg)); | |
| transition: background-color 180ms var(--m-ease); | |
| } | |
| .m-switch::before { | |
| content: ""; position: absolute; left: 3px; top: 3px; width: 18px; height: 18px; border-radius: 999px; | |
| background: var(--bg); box-shadow: 0 1px 3px rgb(0 0 0 / .25); | |
| transform-origin: 0 50%; transition: transform 180ms var(--m-ease); | |
| } | |
| .m-switch[aria-checked="true"] { background: var(--action); } | |
| .m-switch[aria-checked="true"]::before { transform: translateX(16px); background: var(--action-ink); } | |
| .m-switch:active::before { transform: scaleX(1.22); transition-duration: var(--m-press); } | |
| .m-switch[aria-checked="true"]:active::before { transform: translateX(12px) scaleX(1.22); } | |
| .m-switch:hover:not([aria-checked="true"]) { background: color-mix(in oklab, var(--ink) 58%, var(--bg)); } | |
| /* a check box: <input type="checkbox" class="m-check">, the tick fades in as it grows from 70% to full size, 160ms */ | |
| .m-check { | |
| appearance: none; -webkit-appearance: none; flex: none; margin: 0; width: 20px; height: 20px; border-radius: 6px; cursor: pointer; | |
| border: 1px solid color-mix(in oklab, var(--ink) 48%, var(--bg)); background: var(--bg) no-repeat center / 14px 14px; | |
| display: inline-grid; place-items: center; | |
| transition: background-color var(--m-in) var(--m-ease), border-color var(--m-in) var(--m-ease); | |
| } | |
| .m-check::before { | |
| content: ""; width: 10px; height: 6px; margin-top: -2px; border: solid var(--action-ink); border-width: 0 0 2px 2px; | |
| opacity: 0; transform: rotate(-45deg) scale(.7); transform-origin: 50% 50%; | |
| transition: transform 160ms var(--m-ease), opacity 100ms var(--m-ease); | |
| } | |
| .m-check:hover:not(:checked) { border-color: color-mix(in oklab, var(--ink) 64%, var(--bg)); } | |
| .m-check:checked { background-color: var(--action); border-color: var(--action); } | |
| .m-check:checked::before { opacity: 1; transform: rotate(-45deg) scale(1); } | |
| /* ---------------------------------------------------------------- FAQ | |
| Every answer stays open (ST-47, system.css): nothing here opens, closes or animates its height. */ | |
| /* ---------------------------------------------------------------- numbers that tick once */ | |
| [data-m-count] { font-variant-numeric: tabular-nums; } | |
| /* ---------------------------------------------------------------- loops inside a card's panel */ | |
| /* a CSS loop the page writes inside [data-m-loop] runs one cycle in --m-cycle (2.5-4 s) and repeats | |
| while on screen; motion.js pauses it off screen and restarts it on hover (motion.md) */ | |
| [data-m-loop] { --m-cycle: 3.2s; --m-still: 0.6; --m-safe: 48px; } | |
| /* the pause button (a 32px disc 12px in from the bottom-right corner) gets a clear band: content in | |
| the flow ends --m-safe (48px) above the bottom edge, and a fading stage dissolves above that band, | |
| never under the button. Size the panel so the loop's subject sits above the fade */ | |
| [data-m-loop]:not(:has(> .stage)) { padding-bottom: var(--m-safe); } | |
| [data-m-loop] > .stage:is(.stage--fade-b, .stage--fade-br) { bottom: var(--m-safe); } | |
| /* on a phone (as ui.js does) and under reduced motion a loop holds its finished picture: the frame at | |
| --m-still (0-1) of the cycle, set on the loop where the picture is complete */ | |
| @media (max-width: 639px) { | |
| [data-m-loop] * { animation-duration: var(--m-cycle) ; animation-delay: calc(-1 * var(--m-still) * var(--m-cycle)) ; | |
| animation-play-state: paused ; } | |
| } | |
| [data-m-loop].is-m-off *, [data-m-loop].is-m-paused * { animation-play-state: paused ; } | |
| /* ---------------------------------------------------------------- the hero's entrance */ | |
| /* Once on load the hero enters (motion.js enter(), motion.md): the h1 line by line out of word masks, | |
| then its lead, each button and its facts 60ms apart, the picture settling; about 1.1 s. | |
| Markup: data-enter on the hero <section> and the one head line that sets html.m-enter before the | |
| first paint (with its 700ms safety mark, m-enter-done). Only the words wait, and only in that window | |
| until motion.js takes over (.is-entering): no script, reduced motion, print and data-motion="off" | |
| show the hero as written; a script later than the mark finds the words fading in here. | |
| The pictures (a photograph, a window, the collage) are never hidden, so nothing blinks or flashes | |
| the hero's ground: a photograph waits at 1.05 and a window or collage at .98, by the scale property | |
| (it composes with any transform of their own), and they settle by transition as soon as the | |
| entrance starts or the mark passes. */ | |
| @media screen and (prefers-reduced-motion: no-preference) { | |
| html.m-enter:not(.m-enter-done, [data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entering, .is-entered) | |
| :is(h1, h1 ~ *, :has(> h1) ~ *, :has(~ h1)):not([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage, | |
| :has([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage)) { opacity: 0; } | |
| /* the mark passed before motion.js arrived: the words fade in instead of appearing at once */ | |
| html.m-enter.m-enter-done:not([data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entering, .is-entered) | |
| :is(h1, h1 ~ *, :has(> h1) ~ *, :has(~ h1)) { transition: opacity 400ms var(--m-ease); } | |
| /* the settle: a photograph from 1.05 inside its frame (the hero clips one of its own), anything else from .98 */ | |
| html.m-enter:not([data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-still) | |
| :is(:is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):is(img, picture, video), | |
| :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage) > :is(img, picture, video, .frame__img)) { | |
| transition: scale 1100ms var(--m-ease-enter), clip-path 1100ms var(--m-ease-enter); | |
| } | |
| /* the clip's resting value, kept below the waiting rule's weight so that one wins while it applies */ | |
| .hero[data-enter] :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):is(img, picture, video) { clip-path: inset(0); } | |
| html.m-enter:not([data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-still) | |
| :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):not(img, picture, video, :has(> :is(img, picture, video, .frame__img))) { | |
| transition: scale 900ms var(--m-ease-enter); | |
| } | |
| html.m-enter:not(.m-enter-done, [data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entering, .is-entered) | |
| :is(:is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):is(img, picture, video), | |
| :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage) > :is(img, picture, video, .frame__img)) { scale: 1.05; } | |
| html.m-enter:not(.m-enter-done, [data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entering, .is-entered) | |
| :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):is(img, picture, video) { clip-path: inset(2.381%); } /* a picture that is itself the media (a band under the header, a full-bleed layer) has no frame: its own clip keeps it inside its box while larger, (1 - 1/1.05) / 2 */ | |
| html.m-enter:not(.m-enter-done, [data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entering, .is-entered) | |
| :is([data-enter-media], .hero__bg, .hero__media, .hero__stage, .hero__art, .hero__window, .hero-visual, .ly-collage):not(img, picture, video, :has(> :is(img, picture, video, .frame__img))) { scale: .98; } | |
| html.m-enter:not([data-motion="off"]) .hero[data-enter]:not([data-enter="off"], .is-entered) { overflow: clip; } | |
| } | |
| /* while it runs: each word of the h1 in its own mask (the masks go when the h1 gets its own nodes back) */ | |
| .hero[data-enter] .m-w { display: inline-block; overflow: clip; vertical-align: top; padding-bottom: .12em; margin-bottom: -.12em; } | |
| .hero[data-enter] .m-w__in { display: inline-block; } | |
| /* ---------------------------------------------------------------- reduced motion */ | |
| @media (prefers-reduced-motion: reduce) { | |
| html:not([data-motion="off"]) .card:hover, html:not([data-motion="off"]) .card--open:hover > .panel, | |
| html:not([data-motion="off"]) :is(a, .card:has(a), .m-zoom):hover :is(.frame__img, .tile__media > img, img, video), | |
| html:not([data-motion="off"]) .btn:is(:hover, :active), html:not([data-motion="off"]) :is(.btn--arrow, .link):hover::after, | |
| :is(a, button):hover > .m-arrow :is(.m-arrow__head, .m-arrow__stem) { transform: none ; } | |
| .m-arrow__stem { opacity: 1; transform: none; } | |
| html:not([data-motion="off"]) .nav__menu { transform: none ; } | |
| /* the controls keep their state and their colour change, without travel: the tab pill and the switch | |
| knob jump, the tick fades in at full size, the underline is drawn at once */ | |
| .m-tab-ind { transition: none; } | |
| .m-switch::before { transition-property: background-color; } | |
| .m-switch:active::before { transform: none; } | |
| .m-switch[aria-checked="true"]::before, .m-switch[aria-checked="true"]:active::before { transform: translateX(16px); } | |
| .m-check::before { transform: rotate(-45deg) scale(1); transition-property: opacity; } | |
| html:not([data-motion="off"]) :is(.link, .m-link, p a:not([class]), .footer ul a, .footer .link) { transition-property: color, opacity, background-color, border-color; } | |
| /* a press still shows, as a deeper tone instead of a move */ | |
| html:not([data-motion="off"]) .btn--primary:active { background: color-mix(in oklab, var(--action) 74%, var(--bg)); } | |
| html:not([data-motion="off"]) .btn--secondary:active { background: color-mix(in oklab, var(--bg) 86%, var(--ink)); } | |
| [data-m-loop] * { animation-duration: var(--m-cycle) ; animation-iteration-count: infinite ; | |
| animation-delay: calc(-1 * var(--m-still) * var(--m-cycle)) ; animation-play-state: paused ; } | |
| } | |