# Embroidered felt membership card

> A felt member card with an embroidered patch and a running stitch that sews itself around the edge on hover.

- Category: [Cards](https://library.aimran.es/components/cards)
- Built with: HTML + CSS
- Live editor: https://library.aimran.es/blocks/uv-card-knit-membership
- Library: AIMRAN Library (https://library.aimran.es), free, no sign-up, by Aimran Oukham

## Where to use it

Textiles bring warmth that flat cards lack. This member card layers tiny radial dots into a felt texture, draws a satin-stitched patch with a conic gradient, and sews a dashed SVG stitch around the border through an animated mask each time you hover or focus it. A button swaps the mountain badge for a stitched QR code. It suits clubs, outdoor brands and loyalty programs.

The main color is the golden thread, the second the felt. Change the club name, member data and the mountain in the patch, and keep the card ratio so the stitch follows the edge.

## Code

### HTML

```html
<article class="uvq07-knt"><svg class="sw" viewBox="0 0 300 190" aria-hidden="true"><defs><mask id="uvq07-knt-m"><path class="rv" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" pathLength="1"/></mask></defs><path class="st" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" mask="url(#uvq07-knt-m)"/></svg><div class="in"><span class="pt"><svg class="mo" viewBox="0 0 40 40" aria-hidden="true"><circle class="su" cx="28" cy="13" r="3.4"/><path class="mt" d="M5 30L15 15l5 7 4.5-5.5L35 30z"/><path class="sn" d="M15 15l-2.8 4.2 2.8-1 2.6 1.6z"/></svg><span class="qr" role="img" aria-label="Access QR code"><i class="on"></i><i class="on"></i><i></i><i></i><i></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i class="on"></i><i></i><i></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i class="on"></i><i></i><i></i><i></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i></i></span></span><div class="tx"><p class="k">Member card</p><h3>Club Alpino Cierzo</h3><p class="nm">Lucía Ferrer</p><p class="no">No. 0427 · Since 2019</p><div class="ft"><span>Valid until 12/2027</span><button type="button" aria-expanded="false" data-a="Show QR" data-b="Hide QR">Show QR</button></div></div></div></article>
```

### CSS

```css
.uvq07-knt {
  --c1: #e6b450;
  --c2: #2f4a3a;
  --s: 16px;
  /* tamaño */
  --k: 1;
  /* velocidad */
  --fg: #1d1d1f;
  /* texto */
  --bg: #f5f5f7;
  /* fondo */
}

.uvq07-knt {
  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: 18em;
  aspect-ratio: 300/190;
  box-sizing: border-box;
  padding: 1.1em 1.2em;
  border-radius: 1em;
  color: #f6efe0;
  background: radial-gradient(rgba(255,255,255,.09) .5px,transparent 1px) 0 0/4px 4px,radial-gradient(rgba(0,0,0,.18) .6px,transparent 1.2px) 1px 2px/5px 5px,radial-gradient(130% 100% at 15% 0%,color-mix(in srgb,var(--c2) 80%,#fff),var(--c2) 55%,color-mix(in srgb,var(--c2) 75%,#000));
  box-shadow: 0 1.3em 2.2em -1.2em rgba(0,0,0,.6),inset 0 0 0 1px rgba(255,255,255,.06);
}

.uvq07-knt .sw {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.uvq07-knt .st {
  fill: none;
  stroke: var(--c1);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-dasharray: 7 5;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,.45));
}

.uvq07-knt .rv {
  fill: none;
  stroke: #fff;
  stroke-width: 10;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: uvq07-knt-a calc(2.2s / var(--k)) cubic-bezier(.25,.1,.25,1) both;
}

.uvq07-knt:hover .rv,.uvq07-knt:focus-within .rv {
  animation-name: uvq07-knt-b;
}

.uvq07-knt .in {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1em;
  height: 100%;
}

.uvq07-knt .pt {
  position: relative;
  flex: none;
  width: 5.6em;
  height: 5.6em;
  border-radius: 50%;
  background: radial-gradient(circle closest-side,#efe5cf 0 80%,transparent 81%),repeating-conic-gradient(var(--c1) 0 3deg,color-mix(in srgb,var(--c1) 62%,#4a3200) 3deg 5deg);
  box-shadow: 0 .25em .5em rgba(0,0,0,.4);
}

.uvq07-knt .mo {
  position: absolute;
  inset: .9em;
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .mt {
  fill: var(--c2);
  stroke: #efe5cf;
  stroke-width: .7;
  stroke-dasharray: 1.3 .9;
}

.uvq07-knt .sn {
  fill: #fff;
}

.uvq07-knt .su {
  fill: var(--c1);
  stroke: color-mix(in srgb,var(--c1) 60%,#4a3200);
  stroke-width: .6;
  stroke-dasharray: 1 .8;
}

.uvq07-knt .qr {
  position: absolute;
  inset: 1.25em;
  display: grid;
  grid-template-columns: repeat(7,1fr);
  gap: 1px;
  opacity: 0;
  transform: scale(.6) rotate(-10deg);
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .qr i.on {
  background: #1f2c24;
  border-radius: 1px;
}

.uvq07-knt.qr-on .mo {
  opacity: 0;
  transform: scale(.7) rotate(12deg);
}

.uvq07-knt.qr-on .qr {
  opacity: 1;
  transform: none;
}

.uvq07-knt .tx {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  min-width: 0;
  flex: 1;
}

.uvq07-knt .tx p {
  margin: 0;
}

.uvq07-knt .k {
  font-size: .58em;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  opacity: .7;
}

.uvq07-knt h3 {
  margin: .25em 0 .35em;
  font: 800 1.15em/1.05 "Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  color: transparent;
  background: repeating-linear-gradient(-60deg,var(--c1) 0 .07em,color-mix(in srgb,var(--c1) 65%,#fff) .07em .12em);
  -webkit-background-clip: text;
  background-clip: text;
  filter: drop-shadow(0 .06em 0 rgba(0,0,0,.45));
}

.uvq07-knt .nm {
  font-size: .86em;
  font-weight: 700;
}

.uvq07-knt .no {
  margin-top: .15em!important;
  font: 600 .7em ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  opacity: .75;
}

.uvq07-knt .ft {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .4em;
  margin-top: auto;
}

.uvq07-knt .ft span {
  font-size: .6em;
  opacity: .7;
}

.uvq07-knt button {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  flex: none;
  padding: .45em .8em;
  border-radius: 2em;
  font-size: .7em;
  font-weight: 800;
  color: color-mix(in srgb,var(--c2) 70%,#000);
  background: var(--c1);
  box-shadow: 0 .2em 0 color-mix(in srgb,var(--c1) 55%,#000);
  transition: transform calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1),box-shadow calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1);
}

.uvq07-knt button:hover {
  transform: translateY(-1px);
}

.uvq07-knt button:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 color-mix(in srgb,var(--c1) 55%,#000);
}

.uvq07-knt button:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

@keyframes uvq07-knt-a {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes uvq07-knt-b {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

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

### JavaScript

```js
document.querySelectorAll(".uvq07-knt").forEach(el => {
  const b=el.querySelector("button");b.addEventListener("click",()=>{const on=b.getAttribute("aria-expanded")!=="true";b.setAttribute("aria-expanded",String(on));el.classList.toggle("qr-on",on);b.textContent=on?b.dataset.b:b.dataset.a})
});
```

### 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 = `
.uvq07-knt {
  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: 18em;
  aspect-ratio: 300/190;
  box-sizing: border-box;
  padding: 1.1em 1.2em;
  border-radius: 1em;
  color: #f6efe0;
  background: radial-gradient(rgba(255,255,255,.09) .5px,transparent 1px) 0 0/4px 4px,radial-gradient(rgba(0,0,0,.18) .6px,transparent 1.2px) 1px 2px/5px 5px,radial-gradient(130% 100% at 15% 0%,color-mix(in srgb,var(--c2) 80%,#fff),var(--c2) 55%,color-mix(in srgb,var(--c2) 75%,#000));
  box-shadow: 0 1.3em 2.2em -1.2em rgba(0,0,0,.6),inset 0 0 0 1px rgba(255,255,255,.06);
}

.uvq07-knt .sw {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.uvq07-knt .st {
  fill: none;
  stroke: var(--c1);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-dasharray: 7 5;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,.45));
}

.uvq07-knt .rv {
  fill: none;
  stroke: #fff;
  stroke-width: 10;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: uvq07-knt-a calc(2.2s / var(--k)) cubic-bezier(.25,.1,.25,1) both;
}

.uvq07-knt:hover .rv,.uvq07-knt:focus-within .rv {
  animation-name: uvq07-knt-b;
}

.uvq07-knt .in {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1em;
  height: 100%;
}

.uvq07-knt .pt {
  position: relative;
  flex: none;
  width: 5.6em;
  height: 5.6em;
  border-radius: 50%;
  background: radial-gradient(circle closest-side,#efe5cf 0 80%,transparent 81%),repeating-conic-gradient(var(--c1) 0 3deg,color-mix(in srgb,var(--c1) 62%,#4a3200) 3deg 5deg);
  box-shadow: 0 .25em .5em rgba(0,0,0,.4);
}

.uvq07-knt .mo {
  position: absolute;
  inset: .9em;
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .mt {
  fill: var(--c2);
  stroke: #efe5cf;
  stroke-width: .7;
  stroke-dasharray: 1.3 .9;
}

.uvq07-knt .sn {
  fill: #fff;
}

.uvq07-knt .su {
  fill: var(--c1);
  stroke: color-mix(in srgb,var(--c1) 60%,#4a3200);
  stroke-width: .6;
  stroke-dasharray: 1 .8;
}

.uvq07-knt .qr {
  position: absolute;
  inset: 1.25em;
  display: grid;
  grid-template-columns: repeat(7,1fr);
  gap: 1px;
  opacity: 0;
  transform: scale(.6) rotate(-10deg);
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .qr i.on {
  background: #1f2c24;
  border-radius: 1px;
}

.uvq07-knt.qr-on .mo {
  opacity: 0;
  transform: scale(.7) rotate(12deg);
}

.uvq07-knt.qr-on .qr {
  opacity: 1;
  transform: none;
}

.uvq07-knt .tx {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  min-width: 0;
  flex: 1;
}

.uvq07-knt .tx p {
  margin: 0;
}

.uvq07-knt .k {
  font-size: .58em;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  opacity: .7;
}

.uvq07-knt h3 {
  margin: .25em 0 .35em;
  font: 800 1.15em/1.05 "Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  color: transparent;
  background: repeating-linear-gradient(-60deg,var(--c1) 0 .07em,color-mix(in srgb,var(--c1) 65%,#fff) .07em .12em);
  -webkit-background-clip: text;
  background-clip: text;
  filter: drop-shadow(0 .06em 0 rgba(0,0,0,.45));
}

.uvq07-knt .nm {
  font-size: .86em;
  font-weight: 700;
}

.uvq07-knt .no {
  margin-top: .15em!important;
  font: 600 .7em ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  opacity: .75;
}

.uvq07-knt .ft {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .4em;
  margin-top: auto;
}

.uvq07-knt .ft span {
  font-size: .6em;
  opacity: .7;
}

.uvq07-knt button {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  flex: none;
  padding: .45em .8em;
  border-radius: 2em;
  font-size: .7em;
  font-weight: 800;
  color: color-mix(in srgb,var(--c2) 70%,#000);
  background: var(--c1);
  box-shadow: 0 .2em 0 color-mix(in srgb,var(--c1) 55%,#000);
  transition: transform calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1),box-shadow calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1);
}

.uvq07-knt button:hover {
  transform: translateY(-1px);
}

.uvq07-knt button:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 color-mix(in srgb,var(--c1) 55%,#000);
}

.uvq07-knt button:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

@keyframes uvq07-knt-a {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes uvq07-knt-b {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq07-knt,.uvq07-knt *,.uvq07-knt *::before,.uvq07-knt *::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 b=el.querySelector("button");b.addEventListener("click",()=>{const on=b.getAttribute("aria-expanded")!=="true";b.setAttribute("aria-expanded",String(on));el.classList.toggle("qr-on",on);b.textContent=on?b.dataset.b:b.dataset.a})
}

export default function CardKnitMembership() {
  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": "#e6b450",
          "--c2": "#2f4a3a",
          "--s": "16px",
          "--k": "1",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <article className="uvq07-knt"><svg className="sw" viewBox="0 0 300 190" aria-hidden="true"><defs><mask id="uvq07-knt-m"><path className="rv" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" pathLength="1" /></mask></defs><path className="st" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" mask="url(#uvq07-knt-m)" /></svg><div className="in"><span className="pt"><svg className="mo" viewBox="0 0 40 40" aria-hidden="true"><circle className="su" cx="28" cy="13" r="3.4" /><path className="mt" d="M5 30L15 15l5 7 4.5-5.5L35 30z" /><path className="sn" d="M15 15l-2.8 4.2 2.8-1 2.6 1.6z" /></svg><span className="qr" role="img" aria-label="Access QR code"><i className="on"></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i></i><i></i><i className="on"></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i></span></span><div className="tx"><p className="k">Member card</p><h3>Club Alpino Cierzo</h3><p className="nm">Lucía Ferrer</p><p className="no">No. 0427 · Since 2019</p><div className="ft"><span>Valid until 12/2027</span><button type="button" aria-expanded="false" data-a="Show QR" data-b="Hide QR">Show QR</button></div></div></div></article>
      </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 “Embroidered felt membership card” block (Cards) from AIMRAN Library to my project.

## What it is
A felt member card with an embroidered patch and a running stitch that sews itself around the edge on hover.

## Chosen settings
- Main color: #e6b450
- Secondary color: #2f4a3a
- Size: 16px (from 12 to 24px)
- Speed: 1x (from 0.5 to 2x)
- Text: "Club Alpino Cierzo"

## 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 = `
.uvq07-knt {
  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: 18em;
  aspect-ratio: 300/190;
  box-sizing: border-box;
  padding: 1.1em 1.2em;
  border-radius: 1em;
  color: #f6efe0;
  background: radial-gradient(rgba(255,255,255,.09) .5px,transparent 1px) 0 0/4px 4px,radial-gradient(rgba(0,0,0,.18) .6px,transparent 1.2px) 1px 2px/5px 5px,radial-gradient(130% 100% at 15% 0%,color-mix(in srgb,var(--c2) 80%,#fff),var(--c2) 55%,color-mix(in srgb,var(--c2) 75%,#000));
  box-shadow: 0 1.3em 2.2em -1.2em rgba(0,0,0,.6),inset 0 0 0 1px rgba(255,255,255,.06);
}

.uvq07-knt .sw {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.uvq07-knt .st {
  fill: none;
  stroke: var(--c1);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-dasharray: 7 5;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,.45));
}

.uvq07-knt .rv {
  fill: none;
  stroke: #fff;
  stroke-width: 10;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: uvq07-knt-a calc(2.2s / var(--k)) cubic-bezier(.25,.1,.25,1) both;
}

.uvq07-knt:hover .rv,.uvq07-knt:focus-within .rv {
  animation-name: uvq07-knt-b;
}

.uvq07-knt .in {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1em;
  height: 100%;
}

.uvq07-knt .pt {
  position: relative;
  flex: none;
  width: 5.6em;
  height: 5.6em;
  border-radius: 50%;
  background: radial-gradient(circle closest-side,#efe5cf 0 80%,transparent 81%),repeating-conic-gradient(var(--c1) 0 3deg,color-mix(in srgb,var(--c1) 62%,#4a3200) 3deg 5deg);
  box-shadow: 0 .25em .5em rgba(0,0,0,.4);
}

.uvq07-knt .mo {
  position: absolute;
  inset: .9em;
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .mt {
  fill: var(--c2);
  stroke: #efe5cf;
  stroke-width: .7;
  stroke-dasharray: 1.3 .9;
}

.uvq07-knt .sn {
  fill: #fff;
}

.uvq07-knt .su {
  fill: var(--c1);
  stroke: color-mix(in srgb,var(--c1) 60%,#4a3200);
  stroke-width: .6;
  stroke-dasharray: 1 .8;
}

.uvq07-knt .qr {
  position: absolute;
  inset: 1.25em;
  display: grid;
  grid-template-columns: repeat(7,1fr);
  gap: 1px;
  opacity: 0;
  transform: scale(.6) rotate(-10deg);
  transition: opacity calc(0.35s / var(--k)) cubic-bezier(.25,.1,.25,1),transform calc(0.45s / var(--k)) cubic-bezier(.34,1.56,.64,1);
}

.uvq07-knt .qr i.on {
  background: #1f2c24;
  border-radius: 1px;
}

.uvq07-knt.qr-on .mo {
  opacity: 0;
  transform: scale(.7) rotate(12deg);
}

.uvq07-knt.qr-on .qr {
  opacity: 1;
  transform: none;
}

.uvq07-knt .tx {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  min-width: 0;
  flex: 1;
}

.uvq07-knt .tx p {
  margin: 0;
}

.uvq07-knt .k {
  font-size: .58em;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  opacity: .7;
}

.uvq07-knt h3 {
  margin: .25em 0 .35em;
  font: 800 1.15em/1.05 "Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  color: transparent;
  background: repeating-linear-gradient(-60deg,var(--c1) 0 .07em,color-mix(in srgb,var(--c1) 65%,#fff) .07em .12em);
  -webkit-background-clip: text;
  background-clip: text;
  filter: drop-shadow(0 .06em 0 rgba(0,0,0,.45));
}

.uvq07-knt .nm {
  font-size: .86em;
  font-weight: 700;
}

.uvq07-knt .no {
  margin-top: .15em!important;
  font: 600 .7em ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  opacity: .75;
}

.uvq07-knt .ft {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .4em;
  margin-top: auto;
}

.uvq07-knt .ft span {
  font-size: .6em;
  opacity: .7;
}

.uvq07-knt button {
  font: inherit;
  color: inherit;
  border: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  flex: none;
  padding: .45em .8em;
  border-radius: 2em;
  font-size: .7em;
  font-weight: 800;
  color: color-mix(in srgb,var(--c2) 70%,#000);
  background: var(--c1);
  box-shadow: 0 .2em 0 color-mix(in srgb,var(--c1) 55%,#000);
  transition: transform calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1),box-shadow calc(0.15s / var(--k)) cubic-bezier(.25,.1,.25,1);
}

.uvq07-knt button:hover {
  transform: translateY(-1px);
}

.uvq07-knt button:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 color-mix(in srgb,var(--c1) 55%,#000);
}

.uvq07-knt button:focus-visible {
  outline: 2px solid var(--c1);
  outline-offset: 3px;
}

@keyframes uvq07-knt-a {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes uvq07-knt-b {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@media (prefers-reduced-motion:reduce) {
  .uvq07-knt,.uvq07-knt *,.uvq07-knt *::before,.uvq07-knt *::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 b=el.querySelector("button");b.addEventListener("click",()=>{const on=b.getAttribute("aria-expanded")!=="true";b.setAttribute("aria-expanded",String(on));el.classList.toggle("qr-on",on);b.textContent=on?b.dataset.b:b.dataset.a})
}

export default function CardKnitMembership() {
  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": "#e6b450",
          "--c2": "#2f4a3a",
          "--s": "16px",
          "--k": "1",
          "--fg": "#1d1d1f",
          "--bg": "#f5f5f7",
        } as CSSProperties}
      >
        <article className="uvq07-knt"><svg className="sw" viewBox="0 0 300 190" aria-hidden="true"><defs><mask id="uvq07-knt-m"><path className="rv" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" pathLength="1" /></mask></defs><path className="st" d="M22 8H278A14 14 0 0 1 292 22V168A14 14 0 0 1 278 182H22A14 14 0 0 1 8 168V22A14 14 0 0 1 22 8Z" mask="url(#uvq07-knt-m)" /></svg><div className="in"><span className="pt"><svg className="mo" viewBox="0 0 40 40" aria-hidden="true"><circle className="su" cx="28" cy="13" r="3.4" /><path className="mt" d="M5 30L15 15l5 7 4.5-5.5L35 30z" /><path className="sn" d="M15 15l-2.8 4.2 2.8-1 2.6 1.6z" /></svg><span className="qr" role="img" aria-label="Access QR code"><i className="on"></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i></i><i></i><i className="on"></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i className="on"></i><i></i><i></i><i></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i className="on"></i><i></i><i></i></span></span><div className="tx"><p className="k">Member card</p><h3>Club Alpino Cierzo</h3><p className="nm">Lucía Ferrer</p><p className="no">No. 0427 · Since 2019</p><div className="ft"><span>Valid until 12/2027</span><button type="button" aria-expanded="false" data-a="Show QR" data-b="Hide QR">Show QR</button></div></div></div></article>
      </div>
    </>
  );
}
```

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