# Hourglass timer

> A glass hourglass that counts real seconds; press it and it flips over on a spring to start again.

- Category: [Liquid Glass](https://library.aimran.es/components/liquid-glass)
- Built with: HTML + CSS
- Live editor: https://library.aimran.es/blocks/uv-lg-hourglass
- Library: AIMRAN Library (https://library.aimran.es), free, no sign-up, by Aimran Oukham

## Where to use it

A countdown shaped like an hourglass, drawn in SVG with wooden caps, posts and a glass body with soft highlights. The sand drains from the top bulb, falls in a thin stream and builds a mound below while the time ticks down beside it. Tap the glass and the whole piece flips with an overshoot before restarting.

Set the duration in seconds with its slider and pick the sand and wood colors. It works well for focus timers, cooking steps, quiz rounds or any moment where waiting should feel calm and tangible.

## Code

### HTML

```html
<div class="uvq11-hg"><button type="button" class="hb" aria-label="Turn the hourglass over"><span class="fl"><svg viewBox="0 0 100 170" aria-hidden="true"><defs><clipPath id="uvq11-hg-c"><path d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z"/></clipPath><linearGradient id="uvq11-hg-w" x1="0" x2="1"><stop offset="0" stop-color="#3a2014"/><stop offset=".45" stop-color="#9a6a45"/><stop offset="1" stop-color="#3a2014"/></linearGradient></defs><path class="po" d="M13 12V158M87 12V158"/><g clip-path="url(#uvq11-hg-c)"><path class="sd st" d="M10 34Q50 34 90 34V86H10Z"/><path class="sd sb" d=""/><path class="fa" d="M50 84V150"/></g><path class="gs" d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z"/><path class="hl" d="M27 20C27 46 38 62 44 74M27 150C27 126 38 110 44 98"/><rect x="6" y="3" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)"/><rect x="6" y="157" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)"/></svg></span></button><div class="tx"><output class="tm">0:20</output><span>Turn it over</span></div></div>
```

### CSS

```css
.uvq11-hg {
  --c1: #f2c17d;
  --c2: #6b3f2a;
  --s: 16px;
  /* tamaño */
  --k: 1;
  /* velocidad */
  --du: 20;
  /* duración */
  --fg: #1d1d1f;
  /* texto */
  --bg: #f5f5f7;
  /* fondo */
}

.uvq11-hg {
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Text","Inter",system-ui,sans-serif;
  font-size: var(--s);
  color: var(--fg);
  -webkit-tap-highlight-color: transparent;
  position: relative;
  width: 20em;
  height: 14em;
  border-radius: 1.6em;
  overflow: hidden;
  color: #fff;
  isolation: isolate;
  -webkit-user-select: none;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.6em;
  background: radial-gradient(45% 55% at 30% 50%,rgba(255,196,140,.55),transparent 70%),linear-gradient(160deg,#c0573e,#7a2f3b 55%,#3d1d33);
}

.uvq11-hg .hb {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  display: block;
  width: 6.6em;
  height: 11.2em;
  border-radius: 1em;
}

.uvq11-hg .hb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  outline-offset: 4px;
}

.uvq11-hg .hb::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: -.5em;
  height: .9em;
  border-radius: 50%;
  background: radial-gradient(closest-side,rgba(40,10,10,.5),transparent);
  z-index: -1;
}

.uvq11-hg .fl {
  display: block;
  width: 100%;
  height: 100%;
  transition: transform calc(0.8s / var(--k)) cubic-bezier(.5,-.25,.3,1.35);
}

.uvq11-hg .fl.go {
  transform: rotate(180deg);
}

.uvq11-hg .fl.nt {
  transition: none;
}

.uvq11-hg .hb:active .fl {
  scale: .97;
}

.uvq11-hg svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq11-hg .po {
  stroke: var(--c2);
  stroke-width: 3.4;
  stroke-linecap: round;
}

.uvq11-hg .sd {
  fill: var(--c1);
}

.uvq11-hg .sb {
  fill: color-mix(in srgb,var(--c1) 88%,#7a4a20);
}

.uvq11-hg .fa {
  fill: none;
  stroke: var(--c1);
  stroke-width: 1.6;
  stroke-dasharray: 2 2.5;
  opacity: 0;
}

.uvq11-hg.run .fa {
  opacity: 1;
  animation: uvq11-hg calc(0.4s / var(--k)) linear infinite;
}

.uvq11-hg .gs {
  fill: rgba(255,255,255,.1);
  stroke: rgba(255,255,255,.8);
  stroke-width: 1.3;
}

.uvq11-hg .hl {
  fill: none;
  stroke: rgba(255,255,255,.6);
  stroke-width: 2.6;
  stroke-linecap: round;
}

.uvq11-hg .tx {
  display: grid;
  gap: .3em;
}

.uvq11-hg .tm {
  font-size: 2.6em;
  font-weight: 250;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.uvq11-hg .tx span {
  font-size: .78em;
  font-weight: 600;
  opacity: .75;
}

.uvq11-hg.done .tm {
  animation: uvq11-hg-d calc(0.9s / var(--k)) cubic-bezier(.25,.1,.25,1) 3;
}

@keyframes uvq11-hg {
  to {
    stroke-dashoffset: -9;
  }
}

@keyframes uvq11-hg-d {
  50% {
    opacity: .35;
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq11-hg,.uvq11-hg *,.uvq11-hg *::before,.uvq11-hg *::after {
    animation-duration: .01ms!important;
    animation-iteration-count: 1!important;
    transition-duration: .01ms!important;
  }
}
```

### JavaScript

```js
document.querySelectorAll(".uvq11-hg").forEach(el => {
  const rm=matchMedia("(prefers-reduced-motion: reduce)").matches;const b=el.querySelector(".hb"),fl=el.querySelector(".fl"),st=el.querySelector(".st"),sb=el.querySelector(".sb"),fa=el.querySelector(".fa"),tm=el.querySelector(".tm");let p=0,run=false,last=0,raf=0,busy=false,to=0;
const D=()=>parseFloat(getComputedStyle(el).getPropertyValue("--du"))||20;
const draw=()=>{const q=Math.min(1,p),yt=34+46*Math.pow(q,.75),h=46*Math.pow(q,.9),c=run&&q<1?5:0;st.setAttribute("d",q>=1?"":"M10 "+yt.toFixed(1)+"Q50 "+(yt+c).toFixed(1)+" 90 "+yt.toFixed(1)+"V86H10Z");sb.setAttribute("d",h<.5?"":"M10 160V"+(164-h).toFixed(1)+"Q50 "+(152-h).toFixed(1)+" 90 "+(164-h).toFixed(1)+"V160Z");fa.setAttribute("d","M50 84V"+(156-h).toFixed(1));const s=Math.ceil(D()*(1-q));tm.textContent=Math.floor(s/60)+":"+String(s%60).padStart(2,"0")};
const loop=t=>{const dt=Math.min(100,t-(last||t));last=t;if(run){p+=dt/1000/D();if(p>=1){p=1;run=false;el.classList.remove("run");el.classList.add("done")}draw()}raf=run?requestAnimationFrame(loop):0};
const start=()=>{run=true;last=0;el.classList.add("run");el.classList.remove("done");if(!raf)raf=requestAnimationFrame(loop)};
const done=()=>{if(!busy)return;clearTimeout(to);fl.classList.add("nt");fl.classList.remove("go");p=1-p;draw();void fl.offsetWidth;fl.classList.remove("nt");busy=false;start()};
b.addEventListener("click",()=>{if(busy)return;busy=true;run=false;el.classList.remove("run");if(rm){done();return}fl.classList.add("go");to=setTimeout(done,2500)});
fl.addEventListener("transitionend",e=>{if(e.target===fl)done()});
draw();const t0=setTimeout(start,400);
return()=>{clearTimeout(t0);clearTimeout(to);cancelAnimationFrame(raf)}
});
```

### React

```tsx
// @ts-nocheck: setup() es JavaScript del DOM sin tipos, el mismo de la pestaña JS.
import { useEffect, useRef, type CSSProperties } from "react";

const css = `
.uvq11-hg {
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Text","Inter",system-ui,sans-serif;
  font-size: var(--s);
  color: var(--fg);
  -webkit-tap-highlight-color: transparent;
  position: relative;
  width: 20em;
  height: 14em;
  border-radius: 1.6em;
  overflow: hidden;
  color: #fff;
  isolation: isolate;
  -webkit-user-select: none;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.6em;
  background: radial-gradient(45% 55% at 30% 50%,rgba(255,196,140,.55),transparent 70%),linear-gradient(160deg,#c0573e,#7a2f3b 55%,#3d1d33);
}

.uvq11-hg .hb {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  display: block;
  width: 6.6em;
  height: 11.2em;
  border-radius: 1em;
}

.uvq11-hg .hb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  outline-offset: 4px;
}

.uvq11-hg .hb::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: -.5em;
  height: .9em;
  border-radius: 50%;
  background: radial-gradient(closest-side,rgba(40,10,10,.5),transparent);
  z-index: -1;
}

.uvq11-hg .fl {
  display: block;
  width: 100%;
  height: 100%;
  transition: transform calc(0.8s / var(--k)) cubic-bezier(.5,-.25,.3,1.35);
}

.uvq11-hg .fl.go {
  transform: rotate(180deg);
}

.uvq11-hg .fl.nt {
  transition: none;
}

.uvq11-hg .hb:active .fl {
  scale: .97;
}

.uvq11-hg svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq11-hg .po {
  stroke: var(--c2);
  stroke-width: 3.4;
  stroke-linecap: round;
}

.uvq11-hg .sd {
  fill: var(--c1);
}

.uvq11-hg .sb {
  fill: color-mix(in srgb,var(--c1) 88%,#7a4a20);
}

.uvq11-hg .fa {
  fill: none;
  stroke: var(--c1);
  stroke-width: 1.6;
  stroke-dasharray: 2 2.5;
  opacity: 0;
}

.uvq11-hg.run .fa {
  opacity: 1;
  animation: uvq11-hg calc(0.4s / var(--k)) linear infinite;
}

.uvq11-hg .gs {
  fill: rgba(255,255,255,.1);
  stroke: rgba(255,255,255,.8);
  stroke-width: 1.3;
}

.uvq11-hg .hl {
  fill: none;
  stroke: rgba(255,255,255,.6);
  stroke-width: 2.6;
  stroke-linecap: round;
}

.uvq11-hg .tx {
  display: grid;
  gap: .3em;
}

.uvq11-hg .tm {
  font-size: 2.6em;
  font-weight: 250;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.uvq11-hg .tx span {
  font-size: .78em;
  font-weight: 600;
  opacity: .75;
}

.uvq11-hg.done .tm {
  animation: uvq11-hg-d calc(0.9s / var(--k)) cubic-bezier(.25,.1,.25,1) 3;
}

@keyframes uvq11-hg {
  to {
    stroke-dashoffset: -9;
  }
}

@keyframes uvq11-hg-d {
  50% {
    opacity: .35;
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq11-hg,.uvq11-hg *,.uvq11-hg *::before,.uvq11-hg *::after {
    animation-duration: .01ms!important;
    animation-iteration-count: 1!important;
    transition-duration: .01ms!important;
  }
}
`;

// Interacción en JavaScript del DOM: la misma que en la pestaña JS.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setup(el: any) {
  const rm=matchMedia("(prefers-reduced-motion: reduce)").matches;const b=el.querySelector(".hb"),fl=el.querySelector(".fl"),st=el.querySelector(".st"),sb=el.querySelector(".sb"),fa=el.querySelector(".fa"),tm=el.querySelector(".tm");let p=0,run=false,last=0,raf=0,busy=false,to=0;
const D=()=>parseFloat(getComputedStyle(el).getPropertyValue("--du"))||20;
const draw=()=>{const q=Math.min(1,p),yt=34+46*Math.pow(q,.75),h=46*Math.pow(q,.9),c=run&&q<1?5:0;st.setAttribute("d",q>=1?"":"M10 "+yt.toFixed(1)+"Q50 "+(yt+c).toFixed(1)+" 90 "+yt.toFixed(1)+"V86H10Z");sb.setAttribute("d",h<.5?"":"M10 160V"+(164-h).toFixed(1)+"Q50 "+(152-h).toFixed(1)+" 90 "+(164-h).toFixed(1)+"V160Z");fa.setAttribute("d","M50 84V"+(156-h).toFixed(1));const s=Math.ceil(D()*(1-q));tm.textContent=Math.floor(s/60)+":"+String(s%60).padStart(2,"0")};
const loop=t=>{const dt=Math.min(100,t-(last||t));last=t;if(run){p+=dt/1000/D();if(p>=1){p=1;run=false;el.classList.remove("run");el.classList.add("done")}draw()}raf=run?requestAnimationFrame(loop):0};
const start=()=>{run=true;last=0;el.classList.add("run");el.classList.remove("done");if(!raf)raf=requestAnimationFrame(loop)};
const done=()=>{if(!busy)return;clearTimeout(to);fl.classList.add("nt");fl.classList.remove("go");p=1-p;draw();void fl.offsetWidth;fl.classList.remove("nt");busy=false;start()};
b.addEventListener("click",()=>{if(busy)return;busy=true;run=false;el.classList.remove("run");if(rm){done();return}fl.classList.add("go");to=setTimeout(done,2500)});
fl.addEventListener("transitionend",e=>{if(e.target===fl)done()});
draw();const t0=setTimeout(start,400);
return()=>{clearTimeout(t0);clearTimeout(to);cancelAnimationFrame(raf)}
}

export default function LgHourglass() {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current?.firstElementChild;
    return el ? setup(el) : undefined;
  }, []);

  return (
    <>
      <style>{css}</style>
      <div
        ref={ref} style={{
          "--c1": "#f2c17d",
          "--c2": "#6b3f2a",
          "--s": "16px",
          "--k": "1",
          "--du": "20",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <div className="uvq11-hg"><button type="button" className="hb" aria-label="Turn the hourglass over"><span className="fl"><svg viewBox="0 0 100 170" aria-hidden="true"><defs><clipPath id="uvq11-hg-c"><path d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z" /></clipPath><linearGradient id="uvq11-hg-w" x1="0" x2="1"><stop offset="0" stopColor="#3a2014" /><stop offset=".45" stopColor="#9a6a45" /><stop offset="1" stopColor="#3a2014" /></linearGradient></defs><path className="po" d="M13 12V158M87 12V158" /><g clipPath="url(#uvq11-hg-c)"><path className="sd st" d="M10 34Q50 34 90 34V86H10Z" /><path className="sd sb" d="" /><path className="fa" d="M50 84V150" /></g><path className="gs" d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z" /><path className="hl" d="M27 20C27 46 38 62 44 74M27 150C27 126 38 110 44 98" /><rect x="6" y="3" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)" /><rect x="6" y="157" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)" /></svg></span></button><div className="tx"><output className="tm">0:20</output><span>Turn it over</span></div></div>
      </div>
    </>
  );
}
```

## Prompt for AI assistants

Paste this into ChatGPT, Claude, Cursor, v0 or Lovable to adapt the block to your stack (Tailwind, Vue, Svelte…):

````text
I want to add the “Hourglass timer” block (Liquid Glass) from AIMRAN Library to my project.

## What it is
A glass hourglass that counts real seconds; press it and it flips over on a spring to start again.

## Chosen settings
- Main color: #f2c17d
- Secondary color: #6b3f2a
- Size: 16px (from 12 to 24px)
- Speed: 1x (from 0.5 to 2x)
- Duration: 20s (from 5 to 60s)
- Text: "Dale la vuelta"

## What I need
1. Add it to my project with the same look and animation as the reference code: same sizes, colours, radii, shadows, timings and easing.
2. It is built with plain HTML and CSS (the reference wraps it in a React component with its CSS). If my project uses something else (Vue, Svelte, Astro, plain HTML…), translate it without losing any behaviour. If I use Tailwind, turn the styles into classes; if not, keep the CSS in its own file.
3. Expose the settings above as props (or CSS variables) with those values as defaults.
4. Make it work well on phones: nothing that depends only on hover, touch targets of at least 44 px and no overflow on 320 px screens.
5. Make it look right in light and dark mode.
6. Keep it accessible: semantic HTML, roles and aria-* where needed, visible focus and keyboard support.
7. Respect prefers-reduced-motion: with reduced motion, no big animations but the same end result.

## Reference code
```tsx
// @ts-nocheck: setup() es JavaScript del DOM sin tipos, el mismo de la pestaña JS.
import { useEffect, useRef, type CSSProperties } from "react";

const css = `
.uvq11-hg {
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Text","Inter",system-ui,sans-serif;
  font-size: var(--s);
  color: var(--fg);
  -webkit-tap-highlight-color: transparent;
  position: relative;
  width: 20em;
  height: 14em;
  border-radius: 1.6em;
  overflow: hidden;
  color: #fff;
  isolation: isolate;
  -webkit-user-select: none;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.6em;
  background: radial-gradient(45% 55% at 30% 50%,rgba(255,196,140,.55),transparent 70%),linear-gradient(160deg,#c0573e,#7a2f3b 55%,#3d1d33);
}

.uvq11-hg .hb {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  display: block;
  width: 6.6em;
  height: 11.2em;
  border-radius: 1em;
}

.uvq11-hg .hb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  outline-offset: 4px;
}

.uvq11-hg .hb::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: -.5em;
  height: .9em;
  border-radius: 50%;
  background: radial-gradient(closest-side,rgba(40,10,10,.5),transparent);
  z-index: -1;
}

.uvq11-hg .fl {
  display: block;
  width: 100%;
  height: 100%;
  transition: transform calc(0.8s / var(--k)) cubic-bezier(.5,-.25,.3,1.35);
}

.uvq11-hg .fl.go {
  transform: rotate(180deg);
}

.uvq11-hg .fl.nt {
  transition: none;
}

.uvq11-hg .hb:active .fl {
  scale: .97;
}

.uvq11-hg svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq11-hg .po {
  stroke: var(--c2);
  stroke-width: 3.4;
  stroke-linecap: round;
}

.uvq11-hg .sd {
  fill: var(--c1);
}

.uvq11-hg .sb {
  fill: color-mix(in srgb,var(--c1) 88%,#7a4a20);
}

.uvq11-hg .fa {
  fill: none;
  stroke: var(--c1);
  stroke-width: 1.6;
  stroke-dasharray: 2 2.5;
  opacity: 0;
}

.uvq11-hg.run .fa {
  opacity: 1;
  animation: uvq11-hg calc(0.4s / var(--k)) linear infinite;
}

.uvq11-hg .gs {
  fill: rgba(255,255,255,.1);
  stroke: rgba(255,255,255,.8);
  stroke-width: 1.3;
}

.uvq11-hg .hl {
  fill: none;
  stroke: rgba(255,255,255,.6);
  stroke-width: 2.6;
  stroke-linecap: round;
}

.uvq11-hg .tx {
  display: grid;
  gap: .3em;
}

.uvq11-hg .tm {
  font-size: 2.6em;
  font-weight: 250;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.uvq11-hg .tx span {
  font-size: .78em;
  font-weight: 600;
  opacity: .75;
}

.uvq11-hg.done .tm {
  animation: uvq11-hg-d calc(0.9s / var(--k)) cubic-bezier(.25,.1,.25,1) 3;
}

@keyframes uvq11-hg {
  to {
    stroke-dashoffset: -9;
  }
}

@keyframes uvq11-hg-d {
  50% {
    opacity: .35;
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq11-hg,.uvq11-hg *,.uvq11-hg *::before,.uvq11-hg *::after {
    animation-duration: .01ms!important;
    animation-iteration-count: 1!important;
    transition-duration: .01ms!important;
  }
}
`;

// Interacción en JavaScript del DOM: la misma que en la pestaña JS.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setup(el: any) {
  const rm=matchMedia("(prefers-reduced-motion: reduce)").matches;const b=el.querySelector(".hb"),fl=el.querySelector(".fl"),st=el.querySelector(".st"),sb=el.querySelector(".sb"),fa=el.querySelector(".fa"),tm=el.querySelector(".tm");let p=0,run=false,last=0,raf=0,busy=false,to=0;
const D=()=>parseFloat(getComputedStyle(el).getPropertyValue("--du"))||20;
const draw=()=>{const q=Math.min(1,p),yt=34+46*Math.pow(q,.75),h=46*Math.pow(q,.9),c=run&&q<1?5:0;st.setAttribute("d",q>=1?"":"M10 "+yt.toFixed(1)+"Q50 "+(yt+c).toFixed(1)+" 90 "+yt.toFixed(1)+"V86H10Z");sb.setAttribute("d",h<.5?"":"M10 160V"+(164-h).toFixed(1)+"Q50 "+(152-h).toFixed(1)+" 90 "+(164-h).toFixed(1)+"V160Z");fa.setAttribute("d","M50 84V"+(156-h).toFixed(1));const s=Math.ceil(D()*(1-q));tm.textContent=Math.floor(s/60)+":"+String(s%60).padStart(2,"0")};
const loop=t=>{const dt=Math.min(100,t-(last||t));last=t;if(run){p+=dt/1000/D();if(p>=1){p=1;run=false;el.classList.remove("run");el.classList.add("done")}draw()}raf=run?requestAnimationFrame(loop):0};
const start=()=>{run=true;last=0;el.classList.add("run");el.classList.remove("done");if(!raf)raf=requestAnimationFrame(loop)};
const done=()=>{if(!busy)return;clearTimeout(to);fl.classList.add("nt");fl.classList.remove("go");p=1-p;draw();void fl.offsetWidth;fl.classList.remove("nt");busy=false;start()};
b.addEventListener("click",()=>{if(busy)return;busy=true;run=false;el.classList.remove("run");if(rm){done();return}fl.classList.add("go");to=setTimeout(done,2500)});
fl.addEventListener("transitionend",e=>{if(e.target===fl)done()});
draw();const t0=setTimeout(start,400);
return()=>{clearTimeout(t0);clearTimeout(to);cancelAnimationFrame(raf)}
}

export default function LgHourglass() {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current?.firstElementChild;
    return el ? setup(el) : undefined;
  }, []);

  return (
    <>
      <style>{css}</style>
      <div
        ref={ref} style={{
          "--c1": "#f2c17d",
          "--c2": "#6b3f2a",
          "--s": "16px",
          "--k": "1",
          "--du": "20",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <div className="uvq11-hg"><button type="button" className="hb" aria-label="Turn the hourglass over"><span className="fl"><svg viewBox="0 0 100 170" aria-hidden="true"><defs><clipPath id="uvq11-hg-c"><path d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z" /></clipPath><linearGradient id="uvq11-hg-w" x1="0" x2="1"><stop offset="0" stopColor="#3a2014" /><stop offset=".45" stopColor="#9a6a45" /><stop offset="1" stopColor="#3a2014" /></linearGradient></defs><path className="po" d="M13 12V158M87 12V158" /><g clipPath="url(#uvq11-hg-c)"><path className="sd st" d="M10 34Q50 34 90 34V86H10Z" /><path className="sd sb" d="" /><path className="fa" d="M50 84V150" /></g><path className="gs" d="M20 12H80C80 52 54 70 52 85C54 100 80 118 80 158H20C20 118 46 100 48 85C46 70 20 52 20 12Z" /><path className="hl" d="M27 20C27 46 38 62 44 74M27 150C27 126 38 110 44 98" /><rect x="6" y="3" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)" /><rect x="6" y="157" width="88" height="10" rx="3" fill="url(#uvq11-hg-w)" /></svg></span></button><div className="tx"><output className="tm">0:20</output><span>Turn it over</span></div></div>
      </div>
    </>
  );
}
```

Give me the complete final code, ready to paste, and tell me in one line where to put it in my project.
````
