# Beautycare Mitra: UI-elementen en hero-effecten

Alle links hieronder zijn op 28-09-2026 met Playwright geladen (status 200). De code van de uiverse-elementen is rechtstreeks uit de pagina-data van uiverse.io gehaald. Screenshots van de hero-referenties staan in `temp/fx/`.

Gedeelde tokens voor alle aanpassingen:

```css
:root {
  --creme:     #F6EDE6;
  --zwart:     #15110E;
  --goud:      #A88956;
  --champagne: #D9C7A6;
  --eiken:     #C99A66;
  --font-display: "Bodoni Moda", "Playfair Display", serif;
  --ease-zacht: cubic-bezier(.22, .61, .36, 1); /* geen overshoot, dus geen bounce */
}
```

## UI-elementen

### Lijn die zich om de knop tekent

- **URL:** https://uiverse.io/AmIt-DasIT/evil-wolverine-68
- **Auteur:** AmIt-DasIT
- **Licentie:** MIT (uiverse.io). Staat ook in de lokale bibliotheek: `uiverse-components/buttons/AmIt-DasIT_evil-wolverine-68.json`
- **Waarom het past:** in rust staat er alleen een kort lijnstukje onder de tekst; bij hover loopt die lijn als een pennenstreek rond de hele knop. Dat is hetzelfde gebaar als de gouden lijntekening rond het monogram. Pure SVG + CSS, geen JavaScript.
- **Aanpassing:**
  - `stroke` naar `var(--goud)`, rustdikte 1.5px en hoverdikte 1px (origineel 5px naar 2px is te grof voor een fijne lijn).
  - De rode achtergrond-tint bij hover vervangen door `rgba(168, 137, 86, .08)` op crème, of weglaten.
  - Tekst in `--font-display`, kapitalen, `letter-spacing: .12em`, kleur `--zwart`. De `top: -52px`-hack vervangen door de tekst absoluut te centreren met `inset: 0; display: grid; place-items: center`.
  - Transitie 1s naar 0.9s met `var(--ease-zacht)`. De `dasharray`/`dashoffset` hangen aan de afmetingen (omtrek 2 x (190 + 60) = 500, origineel gebruikt 760 als ruime marge); bij een andere knopmaat herberekenen, of `pathLength="100"` op de `rect` zetten en in procenten werken.
  - Het is een `div`; ombouwen naar `<a>` of `<button>` met `:focus-visible` dat hetzelfde effect geeft als `:hover`.
  - `@media (prefers-reduced-motion: reduce)`: transitie uit, lijn meteen volledig zichtbaar bij hover/focus.

```html
<!-- From Uiverse.io by AmIt-DasIT, MIT -->
<div class="svg-wrapper">
  <svg height="60" width="190" xmlns="http://www.w3.org/2000/svg">
    <rect class="shape" height="60" width="190"></rect>
    </svg>
    <div class="text">Subscribe</div>
</div>
```

```css
.svg-wrapper {
  position: relative;
  width: 190px;
  height: 60px;
  text-align: center;
  cursor: pointer;
}

.shape {
  stroke-dasharray: 100 300;
  stroke-dashoffset: -297;
  fill: transparent;
  stroke: rgb(220, 20, 60);
  stroke-width: 5px;
  transition: stroke-width 1s, stroke-dashoffset 1s, stroke-dasharray 1s;
}

.text {
  font-size: 22px;
  top: -52px;
  position: relative;
  font-weight: 600;
  color: white;
}

.svg-wrapper:hover .shape {
  stroke-width: 2px;
  stroke-dashoffset: 0;
  stroke-dasharray: 760;
}

.svg-wrapper:hover {
  background-color: rgba(220, 20, 60, 0.2);
  transition: 1s;
}
```

### Goudfolie-glans over een omlijnde knop

- **URL:** https://uiverse.io/mobinkakei/silent-kangaroo-88
- **Auteur:** mobinkakei
- **Licentie:** MIT (uiverse.io)
- **Waarom het past:** een dunne schuine lichtstrook (`::after`) glijdt bij hover eenmalig over een witte knop met fijne rand. In goud op crème leest dat als het glimmen van goudfolie op een visitekaartje. Geschikt voor de hoofd-CTA "Afspraak maken".
- **Aanpassing:**
  - **De wiebel eruit.** De keyframes `rotate624` en `storm1261` (knop draait en tekst schudt) vallen onder bounce en passen niet. Alleen de `.btn-shine:after`-veeg houden.
  - Strook: `background: linear-gradient(90deg, transparent, rgba(217, 199, 166, .9), transparent)` (champagne) in plaats van felgroen `#38ef7d`, opacity .6, breedte 40px.
  - Knop: achtergrond `--creme`, rand `1px solid var(--goud)`, `border-radius: 2px` (10px is te zacht voor de Didone-stijl), tekst `--zwart` in `--font-display`, kapitalen.
  - Variant op donker: achtergrond `--zwart`, tekst en rand `--champagne`, strook met iets meer opacity.
  - Veeg 550ms naar 900ms, de bestaande `cubic-bezier(0.19, 1, 0.22, 1)` kan blijven (die schiet niet door).
  - `prefers-reduced-motion`: strook verbergen, alleen een kleurwissel van de rand naar `--eiken`.

```html
<!-- From Uiverse.io by mobinkakei, MIT -->
<button class="btn-shine">
    <span>Shine</span>
</button>
```

```css
button {
  position: relative;
  margin: 0;
  padding: 17px 35px;
  outline: none;
  text-decoration: none;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  text-transform: uppercase;
  background-color: #fff;
  border: 1px solid rgba(22, 76, 167, 0.6);
  border-radius: 10px;
  color: #1d89ff;
  font-weight: 400;
  font-family: inherit;
  z-index: 0;
  overflow: hidden;
  transition: all 0.3s cubic-bezier(0.02, 0.01, 0.47, 1);
}

button span {
  color: #164ca7;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.7px;
}

button:hover {
  animation: rotate624 0.7s ease-in-out both;
}

button:hover span {
  animation: storm1261 0.7s ease-in-out both;
  animation-delay: 0.06s;
}

@keyframes rotate624 {
  0% { transform: rotate(0deg) translate3d(0, 0, 0); }
  25% { transform: rotate(3deg) translate3d(0, 0, 0); }
  50% { transform: rotate(-3deg) translate3d(0, 0, 0); }
  75% { transform: rotate(1deg) translate3d(0, 0, 0); }
  100% { transform: rotate(0deg) translate3d(0, 0, 0); }
}

@keyframes storm1261 {
  0% { transform: translate3d(0, 0, 0) translateZ(0); }
  25% { transform: translate3d(4px, 0, 0) translateZ(0); }
  50% { transform: translate3d(-3px, 0, 0) translateZ(0); }
  75% { transform: translate3d(2px, 0, 0) translateZ(0); }
  100% { transform: translate3d(0, 0, 0) translateZ(0); }
}

.btn-shine {
  border: 1px solid;
  overflow: hidden;
  position: relative;
}

.btn-shine span {
  z-index: 20;
}

.btn-shine:after {
  background: #38ef7d;
  content: "";
  height: 155px;
  left: -75px;
  opacity: 0.4;
  position: absolute;
  top: -50px;
  transform: rotate(35deg);
  transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
  width: 50px;
  z-index: -10;
}

.btn-shine:hover:after {
  left: 120%;
  transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
}
```

### Onderlijn die uitgroeit tot een vlak

- **URL:** https://uiverse.io/garerim/splendid-snail-23
- **Auteur:** garerim
- **Licentie:** MIT (uiverse.io)
- **Waarom het past:** in rust staat er een dun lijntje onder de tekst; bij hover groeit dat lijntje vanuit het midden op tot een vlak achter het woord. Voor secundaire links ("Lees meer over carboxytherapie") en menu-items. Rustig en uitleggend, geen omlijnde knop.
- **Aanpassing:**
  - Lijn `background-color: var(--goud)`, dikte 1px in plaats van 3px, `border-radius: 0`.
  - Vlak bij hover in `--champagne` op crème, tekst blijft `--zwart`. Op een donkere sectie: lijn en vlak `--goud`, tekst wisselt naar `--creme`.
  - De absolute centrering (`position: absolute; top: 50%; left: 50%`) weghalen; die is alleen voor de demo. De knop wordt `position: relative; display: inline-block`, anders valt `.background` met `z-index: -1` achter de sectie-achtergrond (geef de knop `isolation: isolate`).
  - Breedte bij hover 120% naar 108%, zodat het vlak dicht bij het woord blijft. Transitie `.45s var(--ease-zacht)`.
  - Optioneel: een klein SVG-blaadje (uit het logo) dat aan het rechter uiteinde van de lijn meegroeit, met `transform: scale(0 naar 1)` en 100ms vertraging.
  - Tekst in de body-sans, 15 tot 16px, `font-weight: 500`.
  - `prefers-reduced-motion`: geen groei, alleen direct wisselen van lijn naar vlak.

```html
<!-- From Uiverse.io by garerim, MIT -->
<button class="btn">Hover me !
    <div class="background"></div>
</button>
```

```css
.btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 25px;
  font-weight: 600;
  height: 40px;
  line-height: 40px;
  cursor: pointer;
  background-color: inherit;
  border: none;
  outline: none;
  color: #f1f1f1;
}

.btn:hover .background {
  height: inherit;
  width: 120%;
  top: 50%;
}

.btn .background {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, -50%);
  height: 3px;
  width: 100%;
  background-color: #006b92;
  z-index: -1;
  border-radius: 5px;
  transition: all 0.3s;
}
```

### Invulveld met een lijn die opgroeit bij focus

- **URL:** https://uiverse.io/opMorn/tidy-cheetah-73
- **Auteur:** opMorn
- **Licentie:** MIT (uiverse.io)
- **Waarom het past:** voor het afspraak- en contactformulier. Geen kaders, alleen een fijne onderlijn; bij focus trekt een tweede lijn zich van links naar rechts dicht en schuift het label omhoog. Dezelfde lijntaal als de knoppen hierboven, zodat het formulier bij de rest van de site hoort.
- **Aanpassing:**
  - Basislijn `1px solid var(--champagne)`, actieve lijn `var(--goud)` op 1px.
  - `transform-origin: left` voor NL. Voor Farsi (`dir="rtl"`) wordt dat `transform-origin: right` en `left: auto; right: 0` op het label; het veld groeit dan mee met de leesrichting. Dit moet er echt in, want de site is tweetalig.
  - Label in rust `--zwart` op 55% opacity, bij focus `--goud` in kleine kapitalen met `letter-spacing: .1em`.
  - De selector `input[type="text"]` uitbreiden naar `input, textarea` (e-mail, telefoon en bericht).
  - `:valid` alleen gebruiken als het veld `required` is, anders blijft het label op een leeg veld omhoog staan. Voor optionele velden `:not(:placeholder-shown)` met `placeholder=" "` gebruiken.
  - Transitie 0.3s naar .45s `var(--ease-zacht)`.
  - `prefers-reduced-motion`: lijn en label wisselen direct.

```html
<!-- From Uiverse.io by opMorn, MIT -->
<div class="input-container">
  <input required="" id="input" type="text" />
  <label class="label" for="input">Name</label>
  <div class="underline"></div>
</div>
```

```css
.input-container {
  position: relative;
  margin: 50px auto;
  width: 200px;
}

.input-container input[type="text"] {
  font-size: 20px;
  width: 100%;
  border: none;
  border-bottom: 2px solid #ccc;
  padding: 5px 0;
  background-color: transparent;
  outline: none;
}

.input-container .label {
  position: absolute;
  top: 0;
  left: 0;
  color: #ccc;
  transition: all 0.3s ease;
  pointer-events: none;
}

.input-container input[type="text"]:focus ~ .label,
.input-container input[type="text"]:valid ~ .label {
  top: -20px;
  font-size: 16px;
  color: #333;
}

.input-container .underline {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2px;
  width: 100%;
  background-color: #333;
  transform: scaleX(0);
  transition: all 0.3s ease;
}

.input-container input[type="text"]:focus ~ .underline,
.input-container input[type="text"]:valid ~ .underline {
  transform: scaleX(1);
}
```

Niet gevonden: een elegante NL/FA-taalschakelaar. Op uiverse leverde zoeken op "language" bij switches nul resultaten op, en de lokale bibliotheek bevat alleen knoppen (50 stuks). Die toggle bouwen we zelf, in dezelfde lijnstijl.

## Hero-effecten

### Het gouden takje tekent zichzelf

Bij het laden tekenen de twee olijftakjes uit het logo zich met een fijne gouden lijn rond het BM-monogram, van de steel naar de bladpunten, links en rechts net niet gelijk. Daarna verschijnt de kop ("Huidverzorging aan huis in Groningen") met een korte fade, en in dezelfde tekenstijl een Farsi-regel eronder. Het voelt als een pen die het logo nog even zet: persoonlijk, handgemaakt, en het verwijst direct naar haar eigen beeldmerk in plaats van naar een generiek effect. Later op de pagina kan dezelfde tekenlijn terugkomen als scheidingslijn tussen secties of rond de "Wist je dat? / میدونستی؟"-kaartjes.

**Techniek:** het takje als SVG met alleen `stroke`-paden (geen fills; zo nodig een lijnversie laten natekenen). Per pad `pathLength="1"`, `stroke-dasharray: 1; stroke-dashoffset: 1`, animeren naar 0 met CSS-keyframes (1.6 tot 2.2s, `var(--ease-zacht)`, bladeren met 60 tot 120ms stagger). GSAP DrawSVG is een optie als we meer controle willen over de volgorde, maar CSS volstaat hier. `prefers-reduced-motion`: het takje staat er direct, alleen de kop krijgt een fade van 300ms.

**Referenties:**
- https://codepen.io/juliangarnier/pen/ZeEpgd (Julian Garnier, "SVG line drawing animation"): tientallen gekleurde lijnen (een metrokaart) die zichzelf tekenen met anime.js; laat de stroke-dashoffset-techniek op veel paden tegelijk zien. Screenshot: `temp/fx/takje-1-juliangarnier-svg-line-drawing.png`
- https://codepen.io/PointC/pen/MpLVvO (Craig Roblewsky, "Animated handwriting with DrawSVG (GSAP3)"): het woord "Hand" wordt als handschrift geschreven door een pen, met instelbare snelheid; dichtst bij het pen-gevoel dat we voor het takje willen. Screenshot: `temp/fx/takje-2-pointc-drawsvg-handwriting.png`

### Lamellen die opengaan

De hero-foto (behandelruimte of een close-up van huid) zit achter een laag verticale stroken in eikenkleur met smalle zwarte naden, een directe kopie van haar lamellenwand. Bij het laden, of bij de eerste scroll, draaien of krimpen de stroken een voor een van links naar rechts weg, als een jaloezie die opengaat, en komt de foto erachter vrij. Het vertelt zonder woorden "kom binnen", en wie de praktijk later bezoekt herkent de wand. Het effect moet kort blijven (onder de 1.5s), anders gaat het om het effect in plaats van om de foto.

**Techniek:** 12 tot 16 `div`-stroken in een absolute laag boven de foto, met een eiken-textuur of `linear-gradient` in `--eiken` en 2px `--zwart` ertussen. Animatie met `transform: scaleX(1 naar 0)` en `transform-origin` per strook, of `rotateY(0 naar 90deg)` met `perspective` voor echt kantelen. GSAP met `stagger: 0.04` en eventueel ScrollTrigger (zoals de Codrops-demo), of CSS-keyframes met `animation-delay: calc(var(--i) * 40ms)`. De Codrops-demo gebruikt een SVG-mask met rechthoeken; dat werkt ook, maar losse div's zijn makkelijker te stylen als eikenhout. `prefers-reduced-motion`: geen stroken, foto met een fade van 300ms.

**Referenties:**
- https://tympanus.net/Tutorials/SVGMaskScrollTransition/index3.html (Hiroki Watanabe voor Codrops, "On-Scroll SVG Mask Transitions (Vertical Blinds)"; artikel: https://tympanus.net/codrops/2026/03/11/svg-mask-transitions-on-scroll-with-gsap-and-scrolltrigger/): bij scrollen verschijnt een tweede foto in verticale stroken die gestaffeld breder worden over de eerste foto heen. Dit is vrijwel precies het lamellen-idee. Screenshots: `temp/fx/lamellen-1-codrops-vertical-blinds-midden.png` (halverwege, de stroken zijn goed zichtbaar) en `temp/fx/lamellen-1-codrops-vertical-blinds-eind.png`
- https://tympanus.net/Development/SliceRevealer/index3.html (Codrops, "Slice Revealer", demo 3): bij scrollen wordt elke foto in stroken opgebouwd en weer weggehaald; hier horizontaal en trapsgewijs, als voorbeeld van timing en stagger. Screenshots: `temp/fx/lamellen-2-codrops-slice-revealer.png` en `temp/fx/lamellen-2-codrops-slice-revealer-midden.png`

### Een lichtveeg over de kop

Een zachte, warme lichtbaan strijkt eenmalig schuin over de kop in Bodoni, en even later over de hero-foto, alsof de lamp van de laser of de LED-behandeling eroverheen gaat. Op de letters verandert het goud even naar champagne en terug. Het verwijst naar de behandelingen (licht, laser, glow) zonder dat we een klinisch apparaat in beeld zetten. Het werkt het best als laatste stap na het takje of de lamellen, en dan maar één keer, niet in een lus.

**Techniek:** voor tekst `background: linear-gradient(100deg, var(--goud) 40%, var(--champagne) 50%, var(--goud) 60%)` met `background-size: 250%` en `background-clip: text`, en eenmalig `background-position` animeren (1.2s). Voor de foto een `::before` met een schuine semi-transparante crème-gradient die van links naar rechts schuift (`transform: translateX` in plaats van `left`, zodat het op de GPU draait), met `mix-blend-mode: soft-light` voor een warme glans in plaats van wit. Puur CSS; GSAP alleen als het aan de volgorde van de andere hero-stappen moet hangen. `prefers-reduced-motion`: geen veeg, de kop staat meteen in goud.

**Referenties:**
- https://codepen.io/ponycorn/pen/LYRJOxW (Ponycorn, "Golden Animation Effect on Text"): een serif-kop in kapitalen met een gouden glans die over de letters beweegt, boven een productfoto; dicht bij onze kop in Bodoni. Screenshot: `temp/fx/licht-1-ponycorn-golden-text.png`
- https://codepen.io/zhanghx/pen/NZpGBY (zhanghx, "Light Sweep"): een heldere lichtbaan loopt steeds opnieuw over grijze tekst op zwart; laat de background-clip-techniek in zijn kaalste vorm zien. Screenshot (licht halverwege het tweede teken): `temp/fx/licht-2-zhanghx-light-sweep.png`
- https://codepen.io/jackdomleo7/pen/XWmzeNb (Jack Domleo, "Shine image on hover pure CSS animation"): bij hover schuift een schuine witte glans over een zwart-witfoto, met een `::before` en skewX. Dat is de techniek voor de veeg over de hero-foto. Screenshot (glans halverwege): `temp/fx/licht-3-jackdomleo7-image-shine-midden.png`
