# Curved text watch tooltip

> On a smartwatch face, each complication explains its value with text that follows the curve of the bezel.

- Category: [Tooltips](https://library.aimran.es/components/tooltips)
- Built with: HTML + CSS
- Live editor: https://library.aimran.es/blocks/uv-tip-watch-curved
- Library: AIMRAN Library (https://library.aimran.es), free, no sign-up, by Aimran Oukham

## Where to use it

A round smartwatch face with a tick ring, a sweeping seconds dot and four complications for heart rate, steps, weather and battery. Hover or focus one and its explanation appears as curved text along the bezel, set on an SVG textPath, with the letters tightening into place. It suits wearable apps, fitness dashboards and product pages for watches.

The main color tints the steps and weather text, the second the heart rate and battery. Keep each line under about twenty characters so it fits its quarter of the dial, and change the arc offsets to move it.

## Code

### HTML

```html
<div class="uvq08-wch" role="group" aria-label="Watch face"><div class="fc"><svg viewBox="0 0 200 200" aria-hidden="true"><defs><path id="uvq08-wch-a" d="M25 100A75 75 0 0 1 175 100"/><path id="uvq08-wch-b" d="M16 100A84 84 0 0 0 184 100"/></defs><g class="tk"><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(0 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(6 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(12 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(18 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(24 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(30 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(36 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(42 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(48 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(54 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(60 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(66 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(72 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(78 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(84 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(90 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(96 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(102 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(108 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(114 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(120 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(126 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(132 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(138 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(144 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(150 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(156 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(162 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(168 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(174 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(180 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(186 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(192 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(198 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(204 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(210 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(216 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(222 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(228 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(234 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(240 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(246 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(252 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(258 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(264 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(270 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(276 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(282 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(288 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(294 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(300 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(306 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(312 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(318 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(324 100 100)"/><line x1="100" y1="3.5" x2="100" y2="9" class="mj" transform="rotate(330 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(336 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(342 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(348 100 100)"/><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(354 100 100)"/></g><circle class="sd" cx="100" cy="5.5" r="2.2"/><text class="ct c0" id="uvq08-wch-t0"><textPath href="#uvq08-wch-a" startOffset="27%" text-anchor="middle">Heart rate 72 bpm</textPath></text><text class="ct c1" id="uvq08-wch-t1"><textPath href="#uvq08-wch-a" startOffset="73%" text-anchor="middle">8,432 steps</textPath></text><text class="ct c2" id="uvq08-wch-t2"><textPath href="#uvq08-wch-b" startOffset="73%" text-anchor="middle">Cloudy, high 21°</textPath></text><text class="ct c3" id="uvq08-wch-t3"><textPath href="#uvq08-wch-b" startOffset="27%" text-anchor="middle">Battery 64%</textPath></text><text class="tm" x="100" y="111" text-anchor="middle">10:09</text></svg><button type="button" class="k k0" style="--p:72;--r:var(--c2)" aria-label="Heart rate" aria-describedby="uvq08-wch-t0">72</button><button type="button" class="k k1 pk" style="--p:84;--r:var(--c1)" aria-label="Steps" aria-describedby="uvq08-wch-t1">8.4k</button><button type="button" class="k k2" style="--p:0;--r:var(--c1)" aria-label="Weather" aria-describedby="uvq08-wch-t2">18°</button><button type="button" class="k k3" style="--p:64;--r:var(--c2)" aria-label="Battery" aria-describedby="uvq08-wch-t3">64%</button></div></div>
```

### CSS

```css
.uvq08-wch {
  --c1: #ff9f0a;
  --c2: #30d158;
  --s: 16px;
  /* tamaño */
  --k: 1;
  /* velocidad */
  --fg: #1d1d1f;
  /* texto */
  --bg: #f5f5f7;
  /* fondo */
}

.uvq08-wch {
  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;
  padding: 1em;
}

.uvq08-wch .fc {
  position: relative;
  width: 13em;
  height: 13em;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%,#17171a,#000 70%);
  box-shadow: 0 0 0 .5em #2c2c30,0 0 0 .58em #77777d,0 1.4em 2.2em -.6em rgba(0,0,0,.6);
}

.uvq08-wch .fc::after {
  content: "";
  position: absolute;
  right: -.95em;
  top: 50%;
  width: .5em;
  height: 1.6em;
  translate: 0 -50%;
  border-radius: .2em;
  background: linear-gradient(90deg,#55555b,#2c2c30);
}

.uvq08-wch svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq08-wch .tk line {
  stroke: #4a4a4f;
  stroke-width: 1;
}

.uvq08-wch .tk .mj {
  stroke: #c7c7cc;
  stroke-width: 1.6;
}

.uvq08-wch .sd {
  fill: var(--c1);
  transform-origin: 100px 100px;
  animation: uvq08-wch-s 60s linear infinite;
}

.uvq08-wch .tm {
  fill: #f5f5f7;
  font: 600 30px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: -.5px;
}

.uvq08-wch .ct {
  fill: var(--c1);
  font: 700 10.5px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: 4px;
  opacity: 0;
  transition: opacity calc(0.25s / var(--k)) cubic-bezier(.25,.1,.25,1),letter-spacing calc(0.5s / var(--k)) cubic-bezier(.22,1,.36,1);
}

.uvq08-wch .c0,.uvq08-wch .c3 {
  fill: var(--c2);
}

.uvq08-wch .k {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: absolute;
  display: grid;
  place-items: center;
  width: 2.9em;
  height: 2.9em;
  translate: -50% -50%;
  border-radius: 50%;
  font-size: .95em;
  font-weight: 700;
  color: #f5f5f7;
  background: radial-gradient(closest-side,#1c1c1e calc(100% - .24em),transparent calc(100% - .22em)),conic-gradient(var(--r) calc(var(--p) * 1%),#2e2e31 0);
  transition: transform calc(0.3s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq08-wch .k0 {
  left: 32.3%;
  top: 32.3%;
}

.uvq08-wch .k1 {
  left: 67.7%;
  top: 32.3%;
}

.uvq08-wch .k2 {
  left: 67.7%;
  top: 67.7%;
}

.uvq08-wch .k3 {
  left: 32.3%;
  top: 67.7%;
}

.uvq08-wch .k:hover {
  transform: scale(1.08);
}

.uvq08-wch .k:active {
  transform: scale(.94);
}

.uvq08-wch .k:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

.uvq08-wch:has(.k0:is(:hover,:focus-visible,.pk)) .c0,.uvq08-wch:has(.k1:is(:hover,:focus-visible,.pk)) .c1,.uvq08-wch:has(.k2:is(:hover,:focus-visible,.pk)) .c2,.uvq08-wch:has(.k3:is(:hover,:focus-visible,.pk)) .c3 {
  opacity: 1;
  letter-spacing: .6px;
}

@keyframes uvq08-wch-s {
  to {
    transform: rotate(360deg);
  }
}

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

### JavaScript

```js
document.querySelectorAll(".uvq08-wch").forEach(el => {
  const unpk=()=>{el.classList.remove("pk");el.querySelectorAll(".pk").forEach(x=>x.classList.remove("pk"))};el.addEventListener("pointerover",unpk,{once:true});el.addEventListener("focusin",unpk,{once:true});
});
```

### 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 = `
.uvq08-wch {
  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;
  padding: 1em;
}

.uvq08-wch .fc {
  position: relative;
  width: 13em;
  height: 13em;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%,#17171a,#000 70%);
  box-shadow: 0 0 0 .5em #2c2c30,0 0 0 .58em #77777d,0 1.4em 2.2em -.6em rgba(0,0,0,.6);
}

.uvq08-wch .fc::after {
  content: "";
  position: absolute;
  right: -.95em;
  top: 50%;
  width: .5em;
  height: 1.6em;
  translate: 0 -50%;
  border-radius: .2em;
  background: linear-gradient(90deg,#55555b,#2c2c30);
}

.uvq08-wch svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq08-wch .tk line {
  stroke: #4a4a4f;
  stroke-width: 1;
}

.uvq08-wch .tk .mj {
  stroke: #c7c7cc;
  stroke-width: 1.6;
}

.uvq08-wch .sd {
  fill: var(--c1);
  transform-origin: 100px 100px;
  animation: uvq08-wch-s 60s linear infinite;
}

.uvq08-wch .tm {
  fill: #f5f5f7;
  font: 600 30px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: -.5px;
}

.uvq08-wch .ct {
  fill: var(--c1);
  font: 700 10.5px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: 4px;
  opacity: 0;
  transition: opacity calc(0.25s / var(--k)) cubic-bezier(.25,.1,.25,1),letter-spacing calc(0.5s / var(--k)) cubic-bezier(.22,1,.36,1);
}

.uvq08-wch .c0,.uvq08-wch .c3 {
  fill: var(--c2);
}

.uvq08-wch .k {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: absolute;
  display: grid;
  place-items: center;
  width: 2.9em;
  height: 2.9em;
  translate: -50% -50%;
  border-radius: 50%;
  font-size: .95em;
  font-weight: 700;
  color: #f5f5f7;
  background: radial-gradient(closest-side,#1c1c1e calc(100% - .24em),transparent calc(100% - .22em)),conic-gradient(var(--r) calc(var(--p) * 1%),#2e2e31 0);
  transition: transform calc(0.3s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq08-wch .k0 {
  left: 32.3%;
  top: 32.3%;
}

.uvq08-wch .k1 {
  left: 67.7%;
  top: 32.3%;
}

.uvq08-wch .k2 {
  left: 67.7%;
  top: 67.7%;
}

.uvq08-wch .k3 {
  left: 32.3%;
  top: 67.7%;
}

.uvq08-wch .k:hover {
  transform: scale(1.08);
}

.uvq08-wch .k:active {
  transform: scale(.94);
}

.uvq08-wch .k:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

.uvq08-wch:has(.k0:is(:hover,:focus-visible,.pk)) .c0,.uvq08-wch:has(.k1:is(:hover,:focus-visible,.pk)) .c1,.uvq08-wch:has(.k2:is(:hover,:focus-visible,.pk)) .c2,.uvq08-wch:has(.k3:is(:hover,:focus-visible,.pk)) .c3 {
  opacity: 1;
  letter-spacing: .6px;
}

@keyframes uvq08-wch-s {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq08-wch,.uvq08-wch *,.uvq08-wch *::before,.uvq08-wch *::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 unpk=()=>{el.classList.remove("pk");el.querySelectorAll(".pk").forEach(x=>x.classList.remove("pk"))};el.addEventListener("pointerover",unpk,{once:true});el.addEventListener("focusin",unpk,{once:true});
}

export default function TipWatchCurved() {
  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": "#ff9f0a",
          "--c2": "#30d158",
          "--s": "16px",
          "--k": "1",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <div className="uvq08-wch" role="group" aria-label="Watch face"><div className="fc"><svg viewBox="0 0 200 200" aria-hidden="true"><defs><path id="uvq08-wch-a" d="M25 100A75 75 0 0 1 175 100" /><path id="uvq08-wch-b" d="M16 100A84 84 0 0 0 184 100" /></defs><g className="tk"><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(0 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(6 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(12 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(18 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(24 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(30 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(36 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(42 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(48 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(54 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(60 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(66 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(72 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(78 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(84 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(90 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(96 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(102 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(108 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(114 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(120 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(126 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(132 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(138 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(144 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(150 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(156 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(162 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(168 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(174 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(180 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(186 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(192 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(198 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(204 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(210 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(216 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(222 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(228 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(234 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(240 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(246 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(252 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(258 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(264 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(270 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(276 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(282 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(288 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(294 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(300 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(306 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(312 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(318 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(324 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(330 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(336 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(342 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(348 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(354 100 100)" /></g><circle className="sd" cx="100" cy="5.5" r="2.2" /><text className="ct c0" id="uvq08-wch-t0"><textPath href="#uvq08-wch-a" startOffset="27%" textAnchor="middle">Heart rate 72 bpm</textPath></text><text className="ct c1" id="uvq08-wch-t1"><textPath href="#uvq08-wch-a" startOffset="73%" textAnchor="middle">8,432 steps</textPath></text><text className="ct c2" id="uvq08-wch-t2"><textPath href="#uvq08-wch-b" startOffset="73%" textAnchor="middle">Cloudy, high 21°</textPath></text><text className="ct c3" id="uvq08-wch-t3"><textPath href="#uvq08-wch-b" startOffset="27%" textAnchor="middle">Battery 64%</textPath></text><text className="tm" x="100" y="111" textAnchor="middle">10:09</text></svg><button type="button" className="k k0" style={{ "--p": "72", "--r": "var(--c2)" } as CSSProperties} aria-label="Heart rate" aria-describedby="uvq08-wch-t0">72</button><button type="button" className="k k1 pk" style={{ "--p": "84", "--r": "var(--c1)" } as CSSProperties} aria-label="Steps" aria-describedby="uvq08-wch-t1">8.4k</button><button type="button" className="k k2" style={{ "--p": "0", "--r": "var(--c1)" } as CSSProperties} aria-label="Weather" aria-describedby="uvq08-wch-t2">18°</button><button type="button" className="k k3" style={{ "--p": "64", "--r": "var(--c2)" } as CSSProperties} aria-label="Battery" aria-describedby="uvq08-wch-t3">64%</button></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 “Curved text watch tooltip” block (Tooltips) from AIMRAN Library to my project.

## What it is
On a smartwatch face, each complication explains its value with text that follows the curve of the bezel.

## Chosen settings
- Main color: #ff9f0a
- Secondary color: #30d158
- Size: 16px (from 12 to 24px)
- Speed: 1x (from 0.5 to 2x)
- Text: "Esfera del reloj"

## 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 = `
.uvq08-wch {
  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;
  padding: 1em;
}

.uvq08-wch .fc {
  position: relative;
  width: 13em;
  height: 13em;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%,#17171a,#000 70%);
  box-shadow: 0 0 0 .5em #2c2c30,0 0 0 .58em #77777d,0 1.4em 2.2em -.6em rgba(0,0,0,.6);
}

.uvq08-wch .fc::after {
  content: "";
  position: absolute;
  right: -.95em;
  top: 50%;
  width: .5em;
  height: 1.6em;
  translate: 0 -50%;
  border-radius: .2em;
  background: linear-gradient(90deg,#55555b,#2c2c30);
}

.uvq08-wch svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.uvq08-wch .tk line {
  stroke: #4a4a4f;
  stroke-width: 1;
}

.uvq08-wch .tk .mj {
  stroke: #c7c7cc;
  stroke-width: 1.6;
}

.uvq08-wch .sd {
  fill: var(--c1);
  transform-origin: 100px 100px;
  animation: uvq08-wch-s 60s linear infinite;
}

.uvq08-wch .tm {
  fill: #f5f5f7;
  font: 600 30px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: -.5px;
}

.uvq08-wch .ct {
  fill: var(--c1);
  font: 700 10.5px/1 system-ui,-apple-system,sans-serif;
  letter-spacing: 4px;
  opacity: 0;
  transition: opacity calc(0.25s / var(--k)) cubic-bezier(.25,.1,.25,1),letter-spacing calc(0.5s / var(--k)) cubic-bezier(.22,1,.36,1);
}

.uvq08-wch .c0,.uvq08-wch .c3 {
  fill: var(--c2);
}

.uvq08-wch .k {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: absolute;
  display: grid;
  place-items: center;
  width: 2.9em;
  height: 2.9em;
  translate: -50% -50%;
  border-radius: 50%;
  font-size: .95em;
  font-weight: 700;
  color: #f5f5f7;
  background: radial-gradient(closest-side,#1c1c1e calc(100% - .24em),transparent calc(100% - .22em)),conic-gradient(var(--r) calc(var(--p) * 1%),#2e2e31 0);
  transition: transform calc(0.3s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq08-wch .k0 {
  left: 32.3%;
  top: 32.3%;
}

.uvq08-wch .k1 {
  left: 67.7%;
  top: 32.3%;
}

.uvq08-wch .k2 {
  left: 67.7%;
  top: 67.7%;
}

.uvq08-wch .k3 {
  left: 32.3%;
  top: 67.7%;
}

.uvq08-wch .k:hover {
  transform: scale(1.08);
}

.uvq08-wch .k:active {
  transform: scale(.94);
}

.uvq08-wch .k:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

.uvq08-wch:has(.k0:is(:hover,:focus-visible,.pk)) .c0,.uvq08-wch:has(.k1:is(:hover,:focus-visible,.pk)) .c1,.uvq08-wch:has(.k2:is(:hover,:focus-visible,.pk)) .c2,.uvq08-wch:has(.k3:is(:hover,:focus-visible,.pk)) .c3 {
  opacity: 1;
  letter-spacing: .6px;
}

@keyframes uvq08-wch-s {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq08-wch,.uvq08-wch *,.uvq08-wch *::before,.uvq08-wch *::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 unpk=()=>{el.classList.remove("pk");el.querySelectorAll(".pk").forEach(x=>x.classList.remove("pk"))};el.addEventListener("pointerover",unpk,{once:true});el.addEventListener("focusin",unpk,{once:true});
}

export default function TipWatchCurved() {
  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": "#ff9f0a",
          "--c2": "#30d158",
          "--s": "16px",
          "--k": "1",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <div className="uvq08-wch" role="group" aria-label="Watch face"><div className="fc"><svg viewBox="0 0 200 200" aria-hidden="true"><defs><path id="uvq08-wch-a" d="M25 100A75 75 0 0 1 175 100" /><path id="uvq08-wch-b" d="M16 100A84 84 0 0 0 184 100" /></defs><g className="tk"><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(0 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(6 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(12 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(18 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(24 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(30 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(36 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(42 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(48 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(54 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(60 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(66 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(72 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(78 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(84 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(90 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(96 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(102 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(108 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(114 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(120 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(126 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(132 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(138 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(144 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(150 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(156 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(162 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(168 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(174 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(180 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(186 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(192 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(198 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(204 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(210 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(216 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(222 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(228 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(234 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(240 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(246 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(252 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(258 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(264 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(270 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(276 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(282 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(288 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(294 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(300 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(306 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(312 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(318 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(324 100 100)" /><line x1="100" y1="3.5" x2="100" y2="9" className="mj" transform="rotate(330 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(336 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(342 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(348 100 100)" /><line x1="100" y1="3.5" x2="100" y2="6.5" transform="rotate(354 100 100)" /></g><circle className="sd" cx="100" cy="5.5" r="2.2" /><text className="ct c0" id="uvq08-wch-t0"><textPath href="#uvq08-wch-a" startOffset="27%" textAnchor="middle">Heart rate 72 bpm</textPath></text><text className="ct c1" id="uvq08-wch-t1"><textPath href="#uvq08-wch-a" startOffset="73%" textAnchor="middle">8,432 steps</textPath></text><text className="ct c2" id="uvq08-wch-t2"><textPath href="#uvq08-wch-b" startOffset="73%" textAnchor="middle">Cloudy, high 21°</textPath></text><text className="ct c3" id="uvq08-wch-t3"><textPath href="#uvq08-wch-b" startOffset="27%" textAnchor="middle">Battery 64%</textPath></text><text className="tm" x="100" y="111" textAnchor="middle">10:09</text></svg><button type="button" className="k k0" style={{ "--p": "72", "--r": "var(--c2)" } as CSSProperties} aria-label="Heart rate" aria-describedby="uvq08-wch-t0">72</button><button type="button" className="k k1 pk" style={{ "--p": "84", "--r": "var(--c1)" } as CSSProperties} aria-label="Steps" aria-describedby="uvq08-wch-t1">8.4k</button><button type="button" className="k k2" style={{ "--p": "0", "--r": "var(--c1)" } as CSSProperties} aria-label="Weather" aria-describedby="uvq08-wch-t2">18°</button><button type="button" className="k k3" style={{ "--p": "64", "--r": "var(--c2)" } as CSSProperties} aria-label="Battery" aria-describedby="uvq08-wch-t3">64%</button></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.
````
