← alle entries

phone-mockup

FC-0060device-mockupprimitivev1.0.0

Telefoonlijst om een schermontwerp in te zetten: model (notch of dynamic island), staand of liggend, schaal, veilige randen, thuisbalkje. Behuizing standaard --foreground, scherm --background; nul letterlijke kleuren.

zelfde component — andere tokens

Hallo 👋

Deze inhoud blijft binnen de veilige randen.

primitives/ui/phone-mockup.tsx
/**
 * PhoneMockup — een telefoonlijst om een schermontwerp in te zetten: model
 * (notch of dynamic island), staand of liggend, schaal, veilige randen voor
 * de inhoud, thuisbalkje onderin. De inhoud zijn children; een wallpaper is
 * een URL van het project.
 *
 * De bron had twaalf hex-kleuren als presets en een shade()-helper op hex.
 * Hier is de behuizing standaard --foreground (met color-mix voor de
 * lichtval); een project geeft desnoods een eigen `frameColor`-string mee.
 * Het scherm is standaard --background. Nul letterlijke kleuren.
 */

import type * as React from "react";

export type PhoneModel = "14" | "14-pro" | "15" | "15-pro" | "x" | "plain";

export interface PhoneMockupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
  model?: PhoneModel;
  orientation?: "portrait" | "landscape";
  scale?: number;
  /** Kleur van de behuizing; default de tekstkleur van het project. */
  frameColor?: string;
  screenColor?: string;
  wallpaper?: string;
  wallpaperFit?: "cover" | "contain";
  /** Inhoud binnen de veilige randen (default true). */
  safeArea?: boolean;
  showHomeIndicator?: boolean;
  shadow?: boolean;
  children?: React.ReactNode;
}

/* Logische maten per model (px), structureel — uit de bron. */
const SPECS: Record<PhoneModel, { w: number; h: number; radius: number; bezel: number; top: number; bottom: number; notch?: [number, number, number]; island?: [number, number, number] }> = {
  x: { w: 375, h: 812, radius: 50, bezel: 12, top: 47, bottom: 34, notch: [210, 35, 18] },
  "14": { w: 390, h: 844, radius: 56, bezel: 12, top: 47, bottom: 34, notch: [225, 33, 18] },
  "14-pro": { w: 393, h: 852, radius: 56, bezel: 12, top: 59, bottom: 34, island: [126, 37, 20] },
  "15": { w: 393, h: 852, radius: 56, bezel: 12, top: 59, bottom: 34, island: [126, 37, 20] },
  "15-pro": { w: 393, h: 852, radius: 56, bezel: 12, top: 59, bottom: 34, island: [126, 37, 20] },
  plain: { w: 390, h: 844, radius: 56, bezel: 12, top: 16, bottom: 16 },
};

export function PhoneMockup({
  model = "14-pro",
  orientation = "portrait",
  scale = 1,
  frameColor,
  screenColor,
  wallpaper,
  wallpaperFit = "cover",
  safeArea = true,
  showHomeIndicator = true,
  shadow = true,
  className,
  style,
  children,
  ...rest
}: PhoneMockupProps) {
  const s = SPECS[model];
  const liggend = orientation === "landscape";
  const sw = liggend ? s.h : s.w;
  const sh = liggend ? s.w : s.h;
  const uitsnede = s.island ?? s.notch;

  const vars = {
    ["--fp-phone-w" as string]: `${sw + s.bezel * 2}px`,
    ["--fp-phone-h" as string]: `${sh + s.bezel * 2}px`,
    ["--fp-phone-bezel" as string]: `${s.bezel}px`,
    ["--fp-phone-r" as string]: `${s.radius}px`,
    ["--fp-phone-scale" as string]: scale,
    ["--fp-phone-top" as string]: `${safeArea ? s.top : 0}px`,
    ["--fp-phone-bottom" as string]: `${safeArea ? s.bottom : 0}px`,
    ...(frameColor ? { ["--fp-phone-frame" as string]: frameColor } : {}),
    ...(screenColor ? { ["--fp-phone-screen" as string]: screenColor } : {}),
    ...(uitsnede ? { ["--fp-phone-cut-w" as string]: `${uitsnede[0]}px`, ["--fp-phone-cut-h" as string]: `${uitsnede[1]}px`, ["--fp-phone-cut-r" as string]: `${uitsnede[2]}px` } : {}),
  } as React.CSSProperties;

  return (
    <div {...rest} className={["fp-phone", shadow ? "fp-phone--schaduw" : "", className].filter(Boolean).join(" ")} style={{ ...style, ...vars }} aria-label={`Telefoon (${model})`}>
      <div className="fp-phone__lijst">
        <div className="fp-phone__scherm">
          {wallpaper && <div aria-hidden="true" className="fp-phone__wallpaper" style={{ backgroundImage: `url("${wallpaper}")`, backgroundSize: wallpaperFit }} />}
          {uitsnede && <div aria-hidden="true" className={s.island ? "fp-phone__uitsnede fp-phone__uitsnede--island" : "fp-phone__uitsnede fp-phone__uitsnede--notch"} />}
          <div className="fp-phone__inhoud">{children}</div>
          {showHomeIndicator && <div aria-hidden="true" className="fp-phone__thuis" />}
        </div>
      </div>
    </div>
  );
}
primitives/ui/primitives.css
/**
 * Laag-1 primitives — stylesheet.
 * Uitsluitend tokens uit tokens/CONTRACT.md (contract v1): geen letterlijke
 * kleuren, fonts of radii. Structurele geometrie (padding, greep, marges)
 * staat in rem en is gedocumenteerd als aanname in de manifests.
 * Vereist tokens/motion.css naast dit bestand.
 */

/* ── Button ─────────────────────────────────────────────────────────────── */

.fp-btn {
  appearance: none;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.625rem 1rem;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  transition:
    transform var(--motion-instant-duration) var(--motion-instant),
    opacity var(--motion-instant-duration) var(--motion-instant),
    background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-btn:disabled { cursor: default; opacity: 0.5; }
.fp-btn:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
/* Touch-down zonder vertraging; usePress zet data-pressed, ook bij terugslepen. */
.fp-btn[data-pressed] { transform: scale(0.96); }

.fp-btn--primary { background: var(--primary); color: var(--primary-foreground); }
.fp-btn--primary:hover:not(:disabled) { opacity: 0.9; }

.fp-btn--ghost { background: transparent; color: var(--foreground); border-color: var(--border); }
.fp-btn--ghost:hover:not(:disabled) { background: var(--muted); }

/* ── Field / Input ──────────────────────────────────────────────────────── */

.fp-field { display: flex; flex-direction: column; gap: 0.375rem; }
.fp-field__label { font-size: 0.8125rem; font-weight: 500; color: var(--foreground); }

.fp-input {
  appearance: none;
  font: inherit;
  font-size: 0.875rem;
  color: var(--foreground);
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5625rem 0.75rem;
  transition:
    border-color var(--motion-instant-duration) var(--motion-instant),
    background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-input::placeholder { color: var(--muted-foreground); }
/* Rij met trailing-slot: het veld vult de rij, het slot hangt rechts erin. */
.fp-field__row { position: relative; display: flex; }
.fp-field__row .fp-input { width: 100%; }
.fp-input--met-trailing { padding-right: 2.75rem; }
.fp-field__trailing { position: absolute; inset: 0 0.5rem 0 auto; display: flex; align-items: center; color: var(--muted-foreground); }
.fp-input--met-leading { padding-left: 2.25rem; }
.fp-field__leading { position: absolute; inset: 0 auto 0 0.75rem; display: flex; align-items: center; color: var(--muted-foreground); pointer-events: none; }
/* type=search zonder browser-kruisje; type=file met de bestandsknop als deel van het veld. */
.fp-input[type="search"]::-webkit-search-cancel-button,
.fp-input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.fp-input[type="file"] { padding: 0 0.75rem 0 0; color: var(--muted-foreground); font-style: italic; }
.fp-input[type="file"]::file-selector-button {
  margin-right: 0.75rem; padding: 0.5625rem 0.75rem;
  border: 0; border-right: 1px solid var(--border);
  background: transparent; color: var(--foreground);
  font: inherit; font-size: 0.875rem; font-weight: 500; font-style: normal; cursor: pointer;
}
.fp-input:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 1px; }
.fp-input[aria-invalid] { border-color: var(--danger); }

.fp-field__description { margin: 0; font-size: 0.75rem; color: var(--muted-foreground); }
.fp-field__error { margin: 0; font-size: 0.75rem; color: var(--danger); }

/* ── Popover ────────────────────────────────────────────────────────────── */

.fp-popover-anchor { position: relative; display: inline-block; }

.fp-popover {
  position: absolute;
  z-index: 30;
  min-width: 12rem;
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-overlay);
  padding: 0.3125rem;
  opacity: 0;
  visibility: hidden;
  transition:
    transform var(--motion-pop-duration) var(--motion-pop),
    opacity var(--motion-pop-duration) var(--motion-pop),
    visibility 0s linear var(--motion-pop-duration);
}
.fp-popover[data-open] {
  opacity: 1;
  visibility: visible;
  transition:
    transform var(--motion-pop-duration) var(--motion-pop),
    opacity var(--motion-pop-duration) var(--motion-pop);
}

/* Plaatsing + groeirichting: altijd vanuit het anker (transform-origin). */
.fp-popover--bottom-start { top: calc(100% + 0.5rem); left: 0; transform-origin: top left; transform: scale(0.96) translateY(-0.25rem); }
.fp-popover--bottom-end { top: calc(100% + 0.5rem); right: 0; transform-origin: top right; transform: scale(0.96) translateY(-0.25rem); }
.fp-popover--top-start { bottom: calc(100% + 0.5rem); left: 0; transform-origin: bottom left; transform: scale(0.96) translateY(0.25rem); }
.fp-popover--top-end { bottom: calc(100% + 0.5rem); right: 0; transform-origin: bottom right; transform: scale(0.96) translateY(0.25rem); }
.fp-popover[data-open] { transform: scale(1) translateY(0); }

/* ── DateRangeCalendar ──────────────────────────────────────────────────── */

.fp-cal {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
}
.fp-cal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.fp-cal__title { margin: 0; font-size: 0.9375rem; font-weight: 600; }
.fp-cal__nav { display: flex; gap: 0.25rem; }
.fp-cal__navbtn {
  appearance: none; cursor: pointer; font: inherit; line-height: 1;
  width: 1.75rem; height: 1.75rem;
  background: transparent; color: var(--foreground);
  border: 1px solid var(--border); border-radius: calc(var(--radius) - 2px);
  transition: background-color var(--motion-instant-duration) var(--motion-instant),
              transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-cal__navbtn:hover:not(:disabled) { background: var(--muted); }
.fp-cal__navbtn:active:not(:disabled) { transform: scale(0.94); }
.fp-cal__navbtn:disabled { opacity: 0.3; cursor: default; }
.fp-cal__navbtn:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 1px; }

.fp-cal__hint {
  margin: 0 0 0.875rem; padding: 0.5rem 0.75rem;
  font-size: 0.75rem; color: var(--foreground);
  background: var(--muted); border-radius: calc(var(--radius) - 2px);
}

.fp-cal__months { display: grid; grid-template-columns: 1fr; gap: 2rem; }
@media (min-width: 640px) {
  .fp-cal__months[data-months="2"] { grid-template-columns: 1fr 1fr; }
}
.fp-cal__monthlabel {
  margin: 0 0 0.75rem; text-align: center; text-transform: capitalize;
  font-size: 0.8125rem; font-weight: 500;
}
.fp-cal__weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 0.25rem;
  font-size: 0.6875rem; color: var(--muted-foreground); text-align: center;
}
.fp-cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); row-gap: 0.25rem; }

.fp-cal__day {
  appearance: none; font: inherit; font-size: 0.75rem; line-height: 1;
  width: 2.25rem; height: 2.25rem; margin: 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: transparent; color: var(--foreground);
  border: 0; border-radius: 999px; cursor: pointer;
  transition: background-color var(--motion-instant-duration) var(--motion-instant),
              color var(--motion-instant-duration) var(--motion-instant),
              transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-cal__day:active:not(:disabled) { transform: scale(0.92); }
.fp-cal__day:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 1px; }
.fp-cal__day:hover:not(:disabled) { background: var(--muted); }
.fp-cal__day[data-status="past"] { color: var(--muted-foreground); opacity: 0.4; cursor: default; }
.fp-cal__day[data-status="unavailable"] { color: var(--danger); text-decoration: line-through; cursor: not-allowed; }
.fp-cal__day[data-status="pending"] {
  background: color-mix(in srgb, var(--warning) 18%, transparent);
  color: var(--warning); cursor: not-allowed;
}
.fp-cal__day[data-status="selected-start"],
.fp-cal__day[data-status="selected-end"] {
  background: var(--primary); color: var(--primary-foreground); font-weight: 600;
}
.fp-cal__day[data-status="selected-middle"],
.fp-cal__day[data-status="selecting"] { background: var(--muted); }

.fp-cal__legend {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  margin-top: 1.125rem; padding-top: 0.875rem; border-top: 1px solid var(--border);
  font-size: 0.75rem; color: var(--muted-foreground);
}
.fp-cal__legend span { display: inline-flex; align-items: center; gap: 0.375rem; }
.fp-cal__dot { width: 0.75rem; height: 0.75rem; border-radius: 999px; }
.fp-cal__dot--selected { background: var(--primary); }
.fp-cal__dot--pending { background: color-mix(in srgb, var(--warning) 40%, transparent); }
.fp-cal__strike { color: var(--danger); font-size: 0.7rem; }
.fp-cal__footnote { margin-top: 0.75rem; font-size: 0.75rem; color: var(--muted-foreground); }

/* ── Sheet ──────────────────────────────────────────────────────────────── */

.fp-sheet-scrim {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-sheet-scrim[data-open] { opacity: 1; pointer-events: auto; }

.fp-sheet {
  position: fixed;
  z-index: 51;
  left: 50%;
  bottom: 0;
  width: min(35rem, calc(100% - 1.5rem));
  translate: -50% 0; /* centrering los van de y-animatie (transform is van de spring) */
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-overlay);
  padding: 0.625rem 1.375rem 1.75rem;
  touch-action: none;
}
.fp-sheet:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

.fp-sheet__handle {
  width: 2.5rem;
  height: 0.25rem;
  border-radius: calc(var(--radius) / 4);
  background: var(--border);
  margin: 0.25rem auto 1rem;
}

/* ── Gedeeld: alleen voor schermlezers ──────────────────────────────────── */

.fp-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── FolderStack ────────────────────────────────────────────────────────── */

.fp-folder {
  position: relative;
  display: block;
  width: 20rem;
  height: 13rem;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  touch-action: manipulation;
}
.fp-folder:focus-visible {
  outline: 2px solid var(--ring, var(--info));
  outline-offset: 6px;
  border-radius: var(--radius);
}

.fp-folder__back {
  position: relative;
  width: 87.5%;
  height: 100%;
  margin: 0 auto;
  display: flex;
  justify-content: center;
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.fp-folder__sheet {
  position: absolute;
  top: 0.5rem;
  left: 50%;
  margin-left: -4rem; /* halve breedte: centreren los van de waaier-transform */
  width: 8rem;
  height: 9.5rem;
  padding: 0.75rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-overlay);
}

.fp-folder__lines { display: flex; flex-direction: column; gap: 0.5rem; }
.fp-folder__row { display: flex; gap: 0.5rem; }
.fp-folder__line {
  flex: 1;
  height: 0.375rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--muted-foreground) 22%, transparent);
}
.fp-folder__line--head { width: 100%; }

.fp-folder__flap {
  position: absolute;
  inset-inline: 0;
  bottom: -1px;
  z-index: 3;
  height: 11rem;
  transform-origin: bottom;
  display: flex;
  align-items: center;
  justify-content: center;
}
.fp-folder__shape { width: 100%; height: 100%; overflow: visible; }

/* Het labelvlak op de klep: twee ogen en een mond, meer heeft het niet nodig. */
.fp-folder__label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-top: 2rem;
  pointer-events: none;
}
.fp-folder__dots { display: flex; gap: 2.75rem; margin-bottom: 0.625rem; }
.fp-folder__dot {
  width: 0.625rem; height: 0.625rem; border-radius: 999px;
  background: color-mix(in srgb, var(--muted-foreground) 45%, transparent);
}
.fp-folder__bar {
  width: 2.25rem; height: 0.25rem; border-radius: 999px;
  background: color-mix(in srgb, var(--muted-foreground) 45%, transparent);
}

/* ── TextReveal ─────────────────────────────────────────────────────────── */

.fp-reveal { color: inherit; }
.fp-reveal__group { display: inline-block; white-space: nowrap; vertical-align: baseline; }
/* Bewust geen CSS-transition: de scrub is hier de enige motor (§2.6). */
.fp-reveal__unit { display: inline-block; vertical-align: baseline; }

/* ── TaskSteps ──────────────────────────────────────────────────────────── */

.fp-steps { width: 100%; }
.fp-steps ol {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 0.125rem;
}
.fp-steps li {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  height: 1.75rem;
  padding: 0 0.25rem;
}

.fp-steps__mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 1rem; height: 1rem;
  flex-shrink: 0;
}
.fp-steps__mark > * { grid-area: 1 / 1; }

.fp-steps__badge {
  display: grid;
  place-items: center;
  width: 1rem; height: 1rem;
  border-radius: calc(var(--radius) / 2);
}
.fp-steps__badge--klaar {
  color: var(--success);
  background: color-mix(in srgb, var(--success) 14%, transparent);
}
.fp-steps__badge--fout {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 14%, transparent);
}
.fp-steps__spin { color: var(--muted-foreground); display: grid; place-items: center; }
.fp-steps__pip {
  width: 0.3125rem; height: 0.3125rem;
  border-radius: calc(var(--radius) / 4);
  background: var(--border);
}

.fp-steps__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  transition: color var(--motion-instant-duration) var(--motion-instant);
}
.fp-steps li[data-status="klaar"] .fp-steps__label { color: color-mix(in srgb, var(--foreground) 70%, var(--muted-foreground)); }
.fp-steps li[data-status="bezig"] .fp-steps__label { color: var(--foreground); font-weight: 500; }
.fp-steps li[data-status="fout"] .fp-steps__label { color: var(--danger); font-weight: 500; }

/* De loopband op de actieve regel: licht dat over de tekst trekt. */
.fp-steps__label--loopt {
  font-weight: 500;
  color: transparent;
  background-image: linear-gradient(
    90deg,
    var(--muted-foreground) 38%,
    var(--foreground) 50%,
    var(--muted-foreground) 62%
  );
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
}

.fp-steps__meta {
  flex-shrink: 0;
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted-foreground);
  opacity: 0;
  transition: opacity var(--motion-instant-duration) var(--motion-instant);
}
.fp-steps li[data-status="klaar"] .fp-steps__meta { opacity: 1; }

/* ── PressDepth ─────────────────────────────────────────────────────────── */

.fp-depth {
  position: relative;
  display: inline-flex;
  vertical-align: middle;
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  border-radius: var(--radius);
  outline: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  touch-action: manipulation;
}
.fp-depth:disabled { cursor: default; opacity: 0.5; }

.fp-depth__base {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 100%;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--foreground) 18%, var(--muted));
}

.fp-depth__cap {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 2.25rem;
  padding: 0 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--card-foreground);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
}
.fp-depth:focus-visible .fp-depth__cap {
  outline: 2px solid var(--ring, var(--info));
  outline-offset: 2px;
}

/* Bolling: licht van boven, schaduw van onder — weg zodra hij inzakt. */
.fp-depth__sheen {
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  pointer-events: none;
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, var(--card) 70%, var(--background)),
    inset 0 -1px 0 color-mix(in srgb, var(--foreground) 8%, transparent);
}

/* ── ReorderList ────────────────────────────────────────────────────────── */

.fp-reorder { width: 100%; }
.fp-reorder ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 0.375rem;
}
.fp-reorder li {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.625rem 0.75rem;
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: grab;
  outline: none;
  touch-action: pan-x;
  transition:
    border-color var(--motion-instant-duration) var(--motion-instant),
    background-color var(--motion-instant-duration) var(--motion-instant),
    box-shadow var(--motion-instant-duration) var(--motion-instant);
}
.fp-reorder li[data-lifted] { z-index: 1; cursor: grabbing; box-shadow: var(--shadow-overlay); }
.fp-reorder li[data-held] {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 6%, var(--card));
}
.fp-reorder li:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

.fp-reorder__grip {
  flex-shrink: 0;
  display: inline-flex;
  color: var(--border);
  transition: color var(--motion-instant-duration) var(--motion-instant);
}
.fp-reorder li[data-lifted] .fp-reorder__grip,
.fp-reorder li:hover .fp-reorder__grip { color: var(--muted-foreground); }

.fp-reorder__body { flex: 1; min-width: 0; }

/* ── ProgressBar ────────────────────────────────────────────────────────── */

.fp-progress { width: 100%; }
.fp-progress__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; }

.fp-progress__label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.8125rem; font-weight: 500; color: var(--foreground);
}

/* Beide waarden liggen in hetzelfde vak: de kop verspringt niet bij het wisselen. */
.fp-progress__value { display: grid; justify-items: end; flex-shrink: 0; }
.fp-progress__value-face {
  grid-area: 1 / 1;
  white-space: nowrap;
  font-size: 0.75rem; font-weight: 500; line-height: 1.25rem;
  color: var(--muted-foreground);
}
.fp-progress__value-face--num { font-variant-numeric: tabular-nums; }

.fp-progress__track {
  margin-top: 0.5rem;
  padding: 2px;
  border-radius: calc(var(--radius) / 2);
  background: var(--muted);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 8%, transparent);
}
.fp-progress__rail {
  position: relative;
  height: 0.5rem;
  overflow: hidden;
  border-radius: calc(var(--radius) / 3);
}
.fp-progress__fill {
  position: absolute; inset: 0;
  display: block;
  transform-origin: left;
  border-radius: calc(var(--radius) / 3);
  background: var(--primary);
}
.fp-progress__shuttle {
  position: absolute; inset-block: 0; left: 0;
  display: block;
  width: 40%;
  border-radius: calc(var(--radius) / 3);
  background: var(--primary);
}

/* ── OtpInput ───────────────────────────────────────────────────────────── */

.fp-otp { display: inline-flex; flex-direction: column; }
.fp-otp__row { position: relative; display: flex; gap: 0.5rem; }

.fp-otp__cell { position: relative; width: 2.5rem; height: 3rem; }
.fp-otp__cell[data-gap] { margin-left: 0.75rem; }

/* De input is doorzichtig; het zichtbare teken is een eigen laag erboven. */
.fp-otp__input {
  width: 100%; height: 100%;
  border: 2px solid var(--border);
  border-radius: var(--radius);
  background: var(--muted);
  box-shadow: inset 0 1px 2px color-mix(in srgb, var(--foreground) 7%, transparent);
  color: transparent;
  caret-color: transparent;
  font: inherit;
  font-size: 0.9375rem;
  text-align: center;
  outline: none;
  transition:
    background-color var(--motion-instant-duration) var(--motion-instant),
    border-color var(--motion-instant-duration) var(--motion-instant),
    box-shadow var(--motion-instant-duration) var(--motion-instant);
}
.fp-otp__input::selection { background: transparent; }
.fp-otp__input:disabled { opacity: 0.5; }
.fp-otp__input[data-gevuld] { background: var(--card); border-color: color-mix(in srgb, var(--border) 60%, var(--foreground)); box-shadow: none; }
.fp-otp__input[data-actief] { background: var(--card); border-color: var(--ring, var(--info)); box-shadow: none; }
.fp-otp__input[data-status="fout"] { border-color: var(--danger); background: var(--card); box-shadow: none; }
.fp-otp__input[data-status="goed"] { border-color: var(--success); background: var(--card); box-shadow: none; }

.fp-otp__glass {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
}
.fp-otp__char {
  grid-area: 1 / 1;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  color: var(--foreground);
}
.fp-otp__caret {
  grid-area: 1 / 1;
  display: block;
  width: 1.5px; height: 1.0625rem;
  border-radius: 999px;
  background: var(--foreground);
}

.fp-otp__status { display: grid; height: 1rem; margin-top: 0.5rem; }
.fp-otp__message {
  grid-area: 1 / 1;
  font-size: 0.71875rem; line-height: 1rem;
  color: var(--muted-foreground);
}
.fp-otp__message[data-status="fout"] { color: var(--danger); }
.fp-otp__message[data-status="goed"] { color: var(--success); }

/* ── PasswordStrength ───────────────────────────────────────────────────── */

.fp-pw { width: 100%; }
.fp-pw__meter { display: grid; gap: 0.375rem; }
.fp-pw__slot {
  position: relative;
  height: 0.375rem;
  overflow: hidden;
  border-radius: calc(var(--radius) / 4);
  background: var(--muted);
}
.fp-pw__bar {
  position: absolute; inset: 0;
  transform-origin: left;
  border-radius: calc(var(--radius) / 4);
  background: var(--border);
  transition: background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-pw[data-tone="gevaar"] .fp-pw__bar { background: var(--danger); }
.fp-pw[data-tone="let-op"] .fp-pw__bar { background: var(--warning); }
.fp-pw[data-tone="veilig"] .fp-pw__bar { background: var(--success); }

.fp-pw__head {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  height: 1.25rem; margin-top: 0.5rem;
}
/* Alle woorden in één vak: "Zwak" → "Sterk" verschuift niets. */
.fp-pw__labels { display: inline-grid; }
.fp-pw__label {
  grid-area: 1 / 1;
  white-space: nowrap;
  font-size: 0.78125rem; font-weight: 500; line-height: 1.25rem;
  color: var(--muted-foreground);
  transition: color var(--motion-instant-duration) var(--motion-instant);
}
.fp-pw[data-tone="gevaar"] .fp-pw__label { color: var(--danger); }
.fp-pw[data-tone="let-op"] .fp-pw__label { color: var(--warning); }
.fp-pw[data-tone="veilig"] .fp-pw__label { color: var(--success); }

.fp-pw__warn {
  white-space: nowrap;
  font-size: 0.71875rem; line-height: 1.25rem;
  color: var(--warning);
}

.fp-pw__rules { list-style: none; margin: 0.75rem 0 0; padding: 0; display: grid; gap: 0.375rem; }
.fp-pw__rules li { display: flex; align-items: center; gap: 0.5rem; }

.fp-pw__box {
  position: relative;
  display: grid; place-items: center;
  width: 0.875rem; height: 0.875rem;
  flex-shrink: 0;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) / 3);
  color: var(--background);
}
.fp-pw__box-fill {
  position: absolute; inset: 0;
  border-radius: calc(var(--radius) / 4);
  background: var(--success);
}
.fp-pw__tick { position: relative; width: 0.5625rem; height: 0.5625rem; }

.fp-pw__rule-label {
  font-size: 0.78125rem; line-height: 1.25rem;
  color: var(--muted-foreground);
  transition: color var(--motion-instant-duration) var(--motion-instant);
}
.fp-pw__rules li[data-voldaan] .fp-pw__rule-label { color: var(--foreground); }

/* ── ExpandingNav ───────────────────────────────────────────────────────── */

.fp-nav ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 1rem; }

.fp-nav__item {
  --fp-nav-from: var(--primary);
  --fp-nav-to: var(--primary);
  width: 3.75rem;
  height: 3.75rem;
}
/* De maat springt; Framer interpoleert hem met transforms (FLIP), niet per frame layout. */
.fp-nav__item[data-open] { width: 11.25rem; }

.fp-nav__button {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--card);
  color: var(--muted-foreground);
  font: inherit;
  cursor: pointer;
  outline: none;
  overflow: visible;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  box-shadow: var(--shadow-overlay);
  transition: box-shadow var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-nav__button:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 3px; }
.fp-nav__item[data-open] .fp-nav__button { box-shadow: none; }

.fp-nav__wash,
.fp-nav__glow {
  position: absolute;
  border-radius: 999px;
  background: linear-gradient(45deg, var(--fp-nav-from), var(--fp-nav-to));
  opacity: 0;
  transition: opacity var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-nav__wash { inset: 0; }
.fp-nav__glow { inset-inline: 0; top: 0.625rem; height: 100%; filter: blur(15px); z-index: -1; }
.fp-nav__item[data-open] .fp-nav__wash { opacity: 1; }
.fp-nav__item[data-open] .fp-nav__glow { opacity: 0.5; }

.fp-nav__icon { position: relative; display: inline-flex; font-size: 1.5rem; line-height: 1; }
.fp-nav__label {
  position: absolute;
  white-space: nowrap;
  color: var(--primary-foreground);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ── NeonButton ─────────────────────────────────────────────────────────── */

.fp-neon {
  --fp-neon: var(--primary);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  appearance: none; cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-weight: 500; line-height: 1.2;
  color: var(--foreground);
  border: 1px solid transparent; border-radius: 999px;
  transition:
    background-color var(--motion-instant-duration) var(--motion-instant),
    border-color var(--motion-instant-duration) var(--motion-instant),
    color var(--motion-instant-duration) var(--motion-instant),
    transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-neon--sm { padding: 0.25rem 1rem; font-size: 0.8125rem; }
.fp-neon--md { padding: 0.5rem 1.75rem; font-size: 0.875rem; }
.fp-neon--lg { padding: 0.75rem 2.5rem; font-size: 1rem; }

.fp-neon--outline {
  background: color-mix(in srgb, var(--fp-neon) 6%, transparent);
  border-color: color-mix(in srgb, var(--fp-neon) 22%, transparent);
}
.fp-neon--outline:hover { background: transparent; }
.fp-neon--solid { background: var(--fp-neon); color: var(--primary-foreground); }
.fp-neon--solid:hover { border-color: color-mix(in srgb, var(--foreground) 50%, transparent); }
.fp-neon--ghost { background: transparent; }
.fp-neon--ghost:hover { border-color: var(--border); background: color-mix(in srgb, var(--foreground) 8%, transparent); }

.fp-neon[data-pressed] { transform: scale(0.97); }
.fp-neon:disabled { opacity: 0.5; cursor: default; }
.fp-neon:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

/* De lichtlijnen: 1px, driekwart breed, gecentreerd; alleen opacity beweegt. */
.fp-neon__line {
  position: absolute; left: 12.5%; right: 12.5%; height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--fp-neon), transparent);
  opacity: 0;
  transition: opacity var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-neon__line--top { top: -1px; }
.fp-neon__line--bottom { bottom: -1px; }
.fp-neon:hover .fp-neon__line--top,
.fp-neon:focus-visible .fp-neon__line--top,
.fp-neon[data-pressed] .fp-neon__line--top { opacity: 1; }
.fp-neon:hover .fp-neon__line--bottom,
.fp-neon:focus-visible .fp-neon__line--bottom,
.fp-neon[data-pressed] .fp-neon__line--bottom { opacity: 0.3; }

/* ── GradientButton ─────────────────────────────────────────────────────── */

/* Geregistreerde properties: alleen zo kan de browser een verloop-positie
   interpoleren. Dit is verf, geen layout. */
@property --fp-grad-x { syntax: "<percentage>"; inherits: false; initial-value: 11.14%; }
@property --fp-grad-y { syntax: "<percentage>"; inherits: false; initial-value: 140%; }
@property --fp-grad-sx { syntax: "<percentage>"; inherits: false; initial-value: 150%; }
@property --fp-grad-sy { syntax: "<percentage>"; inherits: false; initial-value: 180.06%; }
@property --fp-grad-s1 { syntax: "<percentage>"; inherits: false; initial-value: 37.35%; }
@property --fp-grad-s2 { syntax: "<percentage>"; inherits: false; initial-value: 61.36%; }
@property --fp-grad-s3 { syntax: "<percentage>"; inherits: false; initial-value: 78.42%; }
@property --fp-grad-s4 { syntax: "<percentage>"; inherits: false; initial-value: 89.52%; }
@property --fp-grad-s5 { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --fp-grad-hoek { syntax: "<angle>"; inherits: false; initial-value: 20deg; }

.fp-grad {
  --fp-grad-1: var(--primary);
  --fp-grad-2: color-mix(in srgb, var(--primary) 70%, var(--info));
  --fp-grad-3: color-mix(in srgb, var(--primary) 40%, var(--info));
  --fp-grad-4: color-mix(in srgb, var(--info) 80%, var(--background));
  --fp-grad-5: color-mix(in srgb, var(--info) 55%, var(--background));
  --fp-grad-rand-1: color-mix(in srgb, var(--primary) 70%, transparent);
  --fp-grad-rand-2: color-mix(in srgb, var(--info) 40%, transparent);
  --fp-grad-x: 11.14%; --fp-grad-y: 140%;
  --fp-grad-sx: 150%; --fp-grad-sy: 180.06%;
  --fp-grad-s1: 37.35%; --fp-grad-s2: 61.36%; --fp-grad-s3: 78.42%; --fp-grad-s4: 89.52%; --fp-grad-s5: 100%;
  --fp-grad-hoek: 20deg;

  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 8.25rem; padding: 1rem 2.25rem;
  appearance: none; cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-weight: 600; line-height: 1.2;
  color: var(--primary-foreground);
  border: 2px solid transparent; border-radius: var(--radius);
  background:
    radial-gradient(
      var(--fp-grad-sx) var(--fp-grad-sy) at var(--fp-grad-x) var(--fp-grad-y),
      var(--fp-grad-1) var(--fp-grad-s1),
      var(--fp-grad-2) var(--fp-grad-s2),
      var(--fp-grad-3) var(--fp-grad-s3),
      var(--fp-grad-4) var(--fp-grad-s4),
      var(--fp-grad-5) var(--fp-grad-s5)
    ) padding-box,
    linear-gradient(var(--fp-grad-hoek), var(--fp-grad-rand-1), var(--fp-grad-rand-2)) border-box;
  transition:
    --fp-grad-x var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-y var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-sx var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-sy var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-s1 var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-s2 var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-s3 var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-s4 var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-s5 var(--motion-smooth-duration) var(--motion-smooth),
    --fp-grad-hoek var(--motion-smooth-duration) var(--motion-smooth),
    transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-grad:hover, .fp-grad:focus-visible, .fp-grad[data-pressed] {
  --fp-grad-x: 0%; --fp-grad-y: 91.51%;
  --fp-grad-sx: 120.24%; --fp-grad-sy: 103.18%;
  --fp-grad-s1: 0%; --fp-grad-s2: 8.8%; --fp-grad-s3: 21.44%; --fp-grad-s4: 71.34%; --fp-grad-s5: 85.76%;
  --fp-grad-hoek: 190deg;
}
.fp-grad[data-pressed] { transform: scale(0.97); }
.fp-grad:disabled { opacity: 0.5; cursor: default; }
.fp-grad:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

/* Verloop op de tekstkleur — voor lichte vlakken waar de merkkleur te luid is. */
.fp-grad--contrast {
  --fp-grad-1: var(--foreground);
  --fp-grad-2: color-mix(in srgb, var(--foreground) 80%, var(--muted-foreground));
  --fp-grad-3: color-mix(in srgb, var(--foreground) 55%, var(--muted-foreground));
  --fp-grad-4: var(--muted-foreground);
  --fp-grad-5: color-mix(in srgb, var(--muted-foreground) 70%, var(--background));
  --fp-grad-rand-1: color-mix(in srgb, var(--foreground) 60%, transparent);
  --fp-grad-rand-2: color-mix(in srgb, var(--muted-foreground) 40%, transparent);
  color: var(--background);
}

/* ── HoverRevealButton ──────────────────────────────────────────────────── */

.fp-hreveal {
  position: relative;
  display: inline-grid; place-items: center; overflow: hidden;
  min-width: 8rem; padding: 0.5rem 1.25rem 0.5rem 2.125rem;
  appearance: none; cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-weight: 600; line-height: 1.4;
  color: var(--foreground);
  background: var(--card);
  border: 1px solid var(--border); border-radius: 999px;
  transition: transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-hreveal:disabled { opacity: 0.5; cursor: default; }
.fp-hreveal:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

/* De stip is een cirkel zo breed als de knop, links van het woord; groeien = schalen, niet meten. */
.fp-hreveal__dot {
  position: absolute; left: 1.25rem; top: 50%;
  width: 100%; aspect-ratio: 1;
  border-radius: 50%;
  background: var(--primary);
  transform: translate(-50%, -50%) scale(0.06);
  pointer-events: none;
  transition: transform var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-hreveal:hover .fp-hreveal__dot,
.fp-hreveal:focus-visible .fp-hreveal__dot,
.fp-hreveal[data-pressed] .fp-hreveal__dot { transform: translate(-50%, -50%) scale(2.2); }

.fp-hreveal__rust {
  position: relative; display: inline-block;
  transform: translateX(0.25rem);
  transition:
    transform var(--motion-smooth-duration) var(--motion-smooth),
    opacity var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-hreveal:hover .fp-hreveal__rust,
.fp-hreveal:focus-visible .fp-hreveal__rust,
.fp-hreveal[data-pressed] .fp-hreveal__rust { transform: translateX(3rem); opacity: 0; }

.fp-hreveal__onthuld {
  position: absolute; inset: 0; padding-left: 0.875rem;
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  color: var(--primary-foreground);
  transform: translateX(3rem); opacity: 0;
  transition:
    transform var(--motion-smooth-duration) var(--motion-smooth),
    opacity var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-hreveal:hover .fp-hreveal__onthuld,
.fp-hreveal:focus-visible .fp-hreveal__onthuld,
.fp-hreveal[data-pressed] .fp-hreveal__onthuld { transform: translateX(-0.25rem); opacity: 1; }

/* ── LiquidMetalButton ──────────────────────────────────────────────────── */

.fp-metal {
  position: relative; isolation: isolate;
  display: inline-grid; place-items: center;
  height: 2.875rem; min-width: 2.875rem; padding: 0 1.5rem;
  appearance: none; border: 0; background: transparent;
  cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-size: 0.875rem; line-height: 1;
  color: var(--muted-foreground);
  border-radius: 999px; overflow: hidden;
}
.fp-metal--icon { width: 2.875rem; padding: 0; }
.fp-metal:disabled { opacity: 0.5; cursor: default; }
.fp-metal:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

/* De rand: een afgeknipt vlak met daarin een te groot draaiend vierkant. */
.fp-metal__ring {
  position: absolute; inset: 0; z-index: -2;
  border-radius: 999px; overflow: hidden;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--foreground) 14%, transparent),
    var(--shadow-overlay);
  transition: box-shadow var(--motion-instant-duration) var(--motion-instant);
}
.fp-metal[data-pressed] .fp-metal__ring {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--foreground) 24%, transparent);
}
.fp-metal__sheen {
  position: absolute; left: 50%; top: 50%;
  width: 200%; aspect-ratio: 1;
  translate: -50% -50%;
  background: conic-gradient(
    from 0deg,
    var(--muted-foreground),
    var(--foreground),
    var(--muted),
    color-mix(in srgb, var(--foreground) 70%, var(--muted-foreground)),
    var(--muted-foreground),
    var(--card),
    var(--foreground),
    var(--muted-foreground)
  );
}
/* Het gezicht: van paneel naar bodem, drukt 1px in. */
.fp-metal__face {
  position: absolute; inset: 2px; z-index: -1;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--card), var(--background));
  transition:
    transform var(--motion-instant-duration) var(--motion-instant),
    box-shadow var(--motion-instant-duration) var(--motion-instant);
}
.fp-metal[data-pressed] .fp-metal__face {
  transform: translateY(1px) scale(0.98);
  box-shadow: inset 0 2px 4px color-mix(in srgb, var(--foreground) 10%, transparent);
}
.fp-metal__label {
  position: relative; display: inline-flex; align-items: center; gap: 0.375rem;
  white-space: nowrap;
  text-shadow: 0 1px 2px color-mix(in srgb, var(--background) 60%, transparent);
}
.fp-metal__ripple-plek { position: absolute; width: 0; height: 0; pointer-events: none; }
.fp-metal__ripple {
  position: absolute; left: -0.625rem; top: -0.625rem;
  display: block; width: 1.25rem; height: 1.25rem;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--foreground) 40%, transparent) 0%, transparent 70%);
}

/* ── LiquidGlassButton ──────────────────────────────────────────────────── */

.fp-glass {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  appearance: none; border: 0; background: transparent;
  cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-weight: 500; line-height: 1;
  color: var(--foreground);
  border-radius: 999px;
  transition: transform var(--motion-smooth-duration) var(--motion-smooth);
}
.fp-glass--md { height: 2.25rem; padding: 0 1rem; font-size: 0.875rem; }
.fp-glass--lg { height: 2.75rem; padding: 0 1.5rem; font-size: 0.9375rem; }
.fp-glass--xl { height: 3.5rem; padding: 0 2.5rem; font-size: 1rem; }
.fp-glass:hover { transform: scale(1.05); }
.fp-glass[data-pressed] { transform: scale(0.98); }
.fp-glass:disabled { opacity: 0.5; cursor: default; }
.fp-glass:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }

/* Lichtval: binnenschaduwen op de tekstkleur — licht op donker, donker op licht. */
.fp-glass__rand {
  position: absolute; inset: 0; z-index: -1;
  border-radius: 999px;
  box-shadow:
    0 0 6px color-mix(in srgb, var(--foreground) 3%, transparent),
    0 2px 6px color-mix(in srgb, var(--foreground) 8%, transparent),
    inset 3px 3px 0.5px -3px color-mix(in srgb, var(--foreground) 90%, transparent),
    inset -3px -3px 0.5px -3px color-mix(in srgb, var(--foreground) 85%, transparent),
    inset 1px 1px 1px -0.5px color-mix(in srgb, var(--foreground) 60%, transparent),
    inset -1px -1px 1px -0.5px color-mix(in srgb, var(--foreground) 60%, transparent),
    inset 0 0 6px 6px color-mix(in srgb, var(--foreground) 12%, transparent),
    inset 0 0 2px 2px color-mix(in srgb, var(--foreground) 6%, transparent),
    0 0 12px color-mix(in srgb, var(--background) 15%, transparent);
}
/* De breking; zonder SVG-backdrop (Safari/Firefox) blijft deze blur staan. */
.fp-glass__laag {
  position: absolute; inset: 0; z-index: -2;
  border-radius: 999px; overflow: hidden;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.fp-glass__inhoud { position: relative; pointer-events: none; }
.fp-glass__filter { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ── DancingLetters ─────────────────────────────────────────────────────── */

.fp-dance {
  display: inline-flex; flex-wrap: wrap; justify-content: center;
  perspective: 1000px;
  user-select: none;
  color: inherit; font: inherit; font-weight: 700;
}
.fp-dance__letter {
  position: relative; display: inline-block;
  transform-style: preserve-3d;
  cursor: pointer; white-space: pre;
}
.fp-dance__letter[data-bezig] { z-index: 1; }

/* ── ShiningText ────────────────────────────────────────────────────────── */

.fp-shine {
  display: inline-block;
  color: transparent;
  background-image: linear-gradient(110deg, var(--muted-foreground) 35%, var(--foreground) 50%, var(--muted-foreground) 75%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
}

/* ── Marquee ────────────────────────────────────────────────────────────── */

.fp-marquee {
  --fp-marquee-gap: 2rem;
  display: flex; width: 100%; overflow: hidden;
}
.fp-marquee--verticaal { flex-direction: column; }
.fp-marquee__band {
  display: flex; flex-shrink: 0;
  gap: var(--fp-marquee-gap);
  padding-right: var(--fp-marquee-gap); /* zodat de naad tussen kopie A en B dezelfde ruimte heeft */
  will-change: transform;
}
.fp-marquee--verticaal .fp-marquee__band { flex-direction: column; padding-right: 0; padding-bottom: var(--fp-marquee-gap); }
.fp-marquee__item { display: flex; flex-shrink: 0; align-items: center; }
.fp-marquee--verticaal .fp-marquee__item { width: 100%; }

/* ── ImagesBadge ────────────────────────────────────────────────────────── */

.fp-badge {
  display: inline-flex; align-items: center;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  background: color-mix(in srgb, var(--card) 90%, transparent);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  box-shadow: var(--shadow-overlay);
  color: var(--foreground);
  user-select: none; cursor: default;
}
.fp-badge--tapbaar { cursor: pointer; }
.fp-badge--tapbaar:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-badge--sm { height: 2.25rem; padding: 0 0.875rem 0 0.5rem; gap: 0.5rem; font-size: 0.6875rem; }
.fp-badge--md { height: 2.75rem; padding: 0 1rem 0 0.625rem; gap: 0.625rem; font-size: 0.75rem; }
.fp-badge--lg { height: 3.5rem; padding: 0 1.25rem 0 0.75rem; gap: 0.75rem; font-size: 0.875rem; }

.fp-badge__strook { position: relative; flex-shrink: 0; }
.fp-badge__kaart {
  position: absolute; top: 0.375rem; left: 0;
  width: var(--fp-badge-px); height: var(--fp-badge-px);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; overflow: hidden;
  border: 2px solid var(--card);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--foreground) 18%, transparent);
  background: var(--muted);
}
.fp-badge__kaart img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fp-badge__kaart--circle, .fp-badge__kaart--teller { border-radius: 50%; }
.fp-badge__kaart--rounded { border-radius: var(--radius); }
.fp-badge__kaart--square { border-radius: calc(var(--radius) / 3); }
.fp-badge__rest { font-weight: 600; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
.fp-badge__label { white-space: nowrap; font-weight: 500; line-height: 1; color: color-mix(in srgb, var(--foreground) 80%, transparent); }

/* ── Timeline ───────────────────────────────────────────────────────────── */

.fp-timeline {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
  color: var(--foreground);
}
.fp-timeline--compact { gap: 0.5rem; }
.fp-timeline--default { gap: 1rem; }
.fp-timeline--spacious { gap: 2rem; }
.fp-timeline--horizontal { flex-direction: row; overflow-x: auto; padding-bottom: 1rem; scrollbar-width: thin; }

.fp-timeline__item { position: relative; display: flex; gap: 0.75rem; padding-bottom: 0.5rem; }
.fp-timeline--horizontal .fp-timeline__item { flex-direction: column; min-width: 16rem; flex-shrink: 0; }

/* De lijn naar de volgende stap draagt de status van deze stap. */
.fp-timeline__lijn { position: absolute; background: var(--border); }
.fp-timeline--vertical .fp-timeline__lijn { left: 0.75rem; top: 2.25rem; bottom: -1rem; width: 1px; }
.fp-timeline--horizontal .fp-timeline__lijn { top: 0.75rem; left: 2rem; right: -1rem; height: 1px; }
.fp-timeline__item[data-status="klaar"] .fp-timeline__lijn,
.fp-timeline__item[data-status="bezig"] .fp-timeline__lijn { background: var(--primary); }
.fp-timeline__item[data-status="wacht"] .fp-timeline__lijn { background: color-mix(in srgb, var(--muted-foreground) 30%, transparent); }
.fp-timeline__item[data-status="fout"] .fp-timeline__lijn { background: var(--danger); }

.fp-timeline__stip-vak { position: relative; z-index: 1; display: flex; flex-shrink: 0; }
.fp-timeline__stip {
  display: flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; flex-shrink: 0;
  border-radius: 50%; border: 2px solid var(--border);
  background: var(--background); color: var(--muted-foreground);
  font-size: 0.75rem; font-weight: 500;
}
.fp-timeline__stipje { display: block; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: currentColor; }
.fp-timeline__item[data-status="klaar"] .fp-timeline__stip { border-color: var(--primary); background: var(--primary); color: var(--primary-foreground); }
.fp-timeline__item[data-status="bezig"] .fp-timeline__stip { border-color: var(--primary); color: var(--primary); }
.fp-timeline__item[data-status="wacht"] .fp-timeline__stip { border-color: color-mix(in srgb, var(--muted-foreground) 30%, transparent); }
.fp-timeline__item[data-status="fout"] .fp-timeline__stip { border-color: var(--danger); background: var(--danger); color: var(--primary-foreground); }

.fp-timeline__inhoud { display: flex; flex-direction: column; gap: 0.375rem; min-width: 0; flex: 1; }
.fp-timeline__kop { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem; }
.fp-timeline__titel { margin: 0; font: inherit; font-weight: 500; line-height: 1.25; }
.fp-timeline__tekst { margin: 0; font-size: 0.875rem; line-height: 1.55; color: var(--muted-foreground); }
.fp-timeline__tijd { flex-shrink: 0; font-size: 0.75rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
.fp-timeline__extra { margin-top: 0.375rem; }

/* ── Accordion ──────────────────────────────────────────────────────────── */

.fp-acc { width: 100%; color: var(--foreground); }
.fp-acc__item { border-bottom: 1px solid var(--border); }
.fp-acc__kop { margin: 0; font: inherit; }
.fp-acc__knop {
  display: flex; align-items: flex-start; gap: 1rem; width: 100%;
  padding: 1rem 0;
  appearance: none; background: transparent; border: 0;
  cursor: pointer; text-align: left;
  font: inherit; color: inherit;
  transition: color var(--motion-default-duration) var(--motion-default);
}
.fp-acc__knop:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-acc__titel { flex: 1; }
.fp-acc__vak { overflow: hidden; }
.fp-acc__inhoud { padding: 0 0 1.5rem; color: var(--muted-foreground); line-height: 1.6; }

/* display: de bron — genummerd, kapitalen, gedempt tot je hem opent. */
.fp-acc--display .fp-acc__knop { padding: 1.25rem 0 1.25rem 1.5rem; color: color-mix(in srgb, var(--foreground) 22%, transparent); }
.fp-acc--display .fp-acc__knop:hover { color: color-mix(in srgb, var(--foreground) 55%, transparent); }
.fp-acc--display .fp-acc__item[data-open] .fp-acc__knop { color: var(--primary); }
.fp-acc--display .fp-acc__nummer { font-size: 0.75rem; line-height: 1.6; font-variant-numeric: tabular-nums; }
.fp-acc--display .fp-acc__titel { text-transform: uppercase; font-size: clamp(1.75rem, 4.5vw, 3rem); line-height: 1.05; letter-spacing: -0.01em; }
.fp-acc--display .fp-acc__inhoud { padding: 0 0 1.5rem 3.5rem; }
@media (min-width: 768px) {
  .fp-acc--display .fp-acc__knop { padding-left: 3.5rem; }
  .fp-acc--display .fp-acc__inhoud { padding: 0 5rem 1.5rem; }
}

/* plain: lijstje met chevron. */
.fp-acc--plain .fp-acc__knop { align-items: center; font-weight: 500; }
.fp-acc--plain .fp-acc__knop:hover { color: var(--primary); }
.fp-acc__chevron { flex-shrink: 0; transition: transform var(--motion-default-duration) var(--motion-default); }
.fp-acc__item[data-open] .fp-acc__chevron { transform: rotate(180deg); }

/* ── LinkPreview ────────────────────────────────────────────────────────── */

.fp-lpreview { position: relative; display: inline-block; }
.fp-lpreview__link { color: inherit; font-weight: 600; text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 35%, transparent); text-underline-offset: 0.15em; }
.fp-lpreview__link:hover { text-decoration-color: currentColor; }
.fp-lpreview__link:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; border-radius: calc(var(--radius) / 3); }
/* Het kaartje hangt boven de link, gecentreerd; transform-origin onderaan zodat het uit de link groeit. */
.fp-lpreview__kaart {
  position: absolute; bottom: calc(100% + 0.625rem); left: 50%;
  margin-left: calc(var(--fp-lpreview-w, 200px) / -2 - 0.25rem);
  z-index: 20;
  display: block; padding: 0.25rem;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-overlay);
  transform-origin: bottom center;
  pointer-events: none;
  font-size: 0;
}
.fp-lpreview__kaart img { display: block; border-radius: calc(var(--radius) - 0.25rem); object-fit: cover; }

/* ── RadioGlider ────────────────────────────────────────────────────────── */

.fp-glider { position: relative; display: flex; flex-direction: column; padding-left: 0.75rem; color: var(--foreground); }
.fp-glider__optie { position: relative; z-index: 2; padding: 0.25rem 0; }
.fp-glider__input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; z-index: 3; appearance: none; }
.fp-glider__input:disabled { cursor: default; }
.fp-glider__label {
  display: block; padding: 0.5rem 0.25rem; cursor: pointer;
  font-size: 1.25rem; color: var(--muted-foreground);
  transition: color var(--motion-default-duration) var(--motion-default);
}
.fp-glider__input:checked + .fp-glider__label { color: var(--primary); }
.fp-glider__input:disabled + .fp-glider__label { opacity: 0.5; cursor: default; }
.fp-glider__input:focus-visible + .fp-glider__label { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; border-radius: calc(var(--radius) / 2); }

/* De rail links: 1px, vervagend naar boven en onder; de streep is 1/n hoog. */
.fp-glider__rail {
  position: absolute; left: 0; top: 0; bottom: 0; width: 1px;
  background: linear-gradient(to bottom, transparent, var(--border), transparent);
}
.fp-glider__streep {
  position: relative; display: block; width: 100%;
  height: calc(100% / var(--fp-glider-n, 3));
  background: linear-gradient(to bottom, transparent, var(--primary), transparent);
  transition: transform var(--motion-playful-duration) var(--motion-playful);
}
.fp-glider__gloed {
  position: absolute; top: 50%; left: 0; width: 300%; height: 60%;
  transform: translateY(-50%);
  background: var(--primary); filter: blur(10px);
}
.fp-glider__waas {
  position: absolute; left: 0; top: 0; height: 100%; width: 9rem;
  background: linear-gradient(to right, color-mix(in srgb, var(--primary) 10%, transparent), transparent);
}

/* ── Toggle ─────────────────────────────────────────────────────────────── */

.fp-toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  appearance: none; cursor: pointer; user-select: none; touch-action: manipulation;
  font: inherit; font-size: 0.875rem; font-weight: 500;
  color: var(--foreground); background: transparent;
  border: 1px solid transparent; border-radius: var(--radius);
  transition:
    background-color var(--motion-instant-duration) var(--motion-instant),
    color var(--motion-instant-duration) var(--motion-instant),
    border-color var(--motion-instant-duration) var(--motion-instant),
    transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-toggle--sm { height: 2.25rem; padding: 0 0.625rem; }
.fp-toggle--md { height: 2.5rem; padding: 0 0.75rem; }
.fp-toggle--lg { height: 2.75rem; padding: 0 1.25rem; }
.fp-toggle--outline { border-color: var(--border); }
.fp-toggle:hover { background: var(--muted); color: var(--muted-foreground); }
.fp-toggle[data-on] { background: color-mix(in srgb, var(--primary) 14%, transparent); color: var(--foreground); }
.fp-toggle[data-pressed] { transform: scale(0.96); }
.fp-toggle:disabled { opacity: 0.5; cursor: default; pointer-events: none; }
.fp-toggle:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-toggle-groep { display: inline-flex; align-items: center; gap: 0.25rem; }
.fp-toggle-groep--vertical { flex-direction: column; align-items: stretch; }
.fp-toggle-groep--vertical .fp-toggle { width: 100%; }

/* ── FileDropzone ───────────────────────────────────────────────────────── */

.fp-drop { width: 100%; display: flex; flex-direction: column; gap: 0.75rem; color: var(--foreground); }
.fp-drop__vak {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 2.5rem 1.5rem; cursor: pointer; text-align: center;
  border: 2px dashed color-mix(in srgb, var(--muted-foreground) 25%, transparent);
  border-radius: var(--radius);
  transition:
    border-color var(--motion-default-duration) var(--motion-default),
    background-color var(--motion-default-duration) var(--motion-default);
}
.fp-drop__vak:hover { border-color: color-mix(in srgb, var(--muted-foreground) 40%, transparent); background: color-mix(in srgb, var(--muted) 30%, transparent); }
.fp-drop__vak[data-boven] { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 5%, transparent); }
.fp-drop__vak[aria-disabled] { opacity: 0.5; pointer-events: none; }
.fp-drop__vak:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-drop__icoon { display: block; margin-bottom: 0.75rem; color: var(--muted-foreground); transition: color var(--motion-default-duration) var(--motion-default); }
.fp-drop__vak[data-boven] .fp-drop__icoon { color: var(--primary); }
/* De tekst wisselt in één vak: geen sprong bij "sleep" → "laat los". */
.fp-drop__tekst-vak { display: grid; }
.fp-drop__tekst { grid-area: 1 / 1; font-size: 0.875rem; font-weight: 500; }
.fp-drop__sub { margin-top: 0.25rem; font-size: 0.75rem; color: var(--muted-foreground); }
.fp-drop__fout { margin: 0; font-size: 0.875rem; color: var(--danger); }
.fp-drop__lijst { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.fp-drop__rij {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border); border-radius: calc(var(--radius) * 0.75);
  background: color-mix(in srgb, var(--muted) 50%, transparent);
}
.fp-drop__rij-icoon { display: flex; color: var(--muted-foreground); }
.fp-drop__rij-tekst { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.fp-drop__naam { font-size: 0.875rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-drop__maat { font-size: 0.75rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
.fp-drop__verwijder {
  display: flex; flex-shrink: 0; padding: 0.25rem;
  appearance: none; border: 0; background: transparent; cursor: pointer;
  color: var(--muted-foreground); border-radius: calc(var(--radius) / 2);
  transition:
    background-color var(--motion-instant-duration) var(--motion-instant),
    color var(--motion-instant-duration) var(--motion-instant),
    transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-drop__verwijder:hover { background: var(--muted); color: var(--foreground); transform: scale(1.1); }
.fp-drop__verwijder[data-pressed] { transform: scale(0.9); }
.fp-drop__verwijder:focus-visible { outline: 2px solid var(--ring, var(--info)); }

/* ── ColorPicker ────────────────────────────────────────────────────────── */

.fp-picker { position: relative; display: grid; place-items: center; width: 16rem; height: 16rem; }
.fp-picker__ring { position: absolute; inset: 0; border-radius: 50%; }
.fp-picker__schijf { position: absolute; inset: 0; border-radius: 50%; background: var(--card); }
.fp-picker__vlak { position: relative; z-index: 1; display: grid; place-items: center; width: 100%; height: 100%; border-radius: 50%; }
.fp-picker__stip {
  position: absolute; left: 50%; top: 50%;
  width: 0.875rem; height: 0.875rem; margin: -0.4375rem 0 0 -0.4375rem;
  appearance: none; border: 0; padding: 0; cursor: pointer;
  border-radius: 50%;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--foreground) 20%, transparent);
}
.fp-picker__stip:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-picker__stip[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--card), 0 0 0 3.5px var(--foreground); }
.fp-picker__stip-ring {
  position: absolute; inset: -0.25rem; border-radius: 50%;
  border: 2px solid currentColor; opacity: 0;
  transition: opacity var(--motion-instant-duration) var(--motion-instant);
}
.fp-picker__stip:hover .fp-picker__stip-ring { opacity: 0.4; }

/* ── Combobox ───────────────────────────────────────────────────────────── */

.fp-combo { display: flex; flex-direction: column; gap: 0.375rem; width: 100%; max-width: 20rem; }
.fp-combo .fp-popover-anchor { display: block; }
.fp-combo__knop { width: 100%; justify-content: space-between; gap: 0.5rem; font-weight: 400; }
.fp-combo__knop svg { flex-shrink: 0; color: var(--muted-foreground); }
.fp-combo__waarde { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-combo__waarde--leeg { color: var(--muted-foreground); }
.fp-combo .fp-popover { width: 100%; padding: 0; }
.fp-combo__paneel { display: flex; flex-direction: column; }
.fp-combo__zoekrij { display: flex; align-items: center; gap: 0.5rem; padding: 0 0.75rem; border-bottom: 1px solid var(--border); color: var(--muted-foreground); }
.fp-combo__zoek {
  flex: 1; min-width: 0; height: 2.5rem;
  appearance: none; border: 0; background: transparent; outline: none;
  font: inherit; font-size: 0.875rem; color: var(--foreground);
}
.fp-combo__zoek::placeholder { color: var(--muted-foreground); }
.fp-combo__lijst { list-style: none; margin: 0; padding: 0.25rem; max-height: 18rem; overflow-y: auto; }
.fp-combo__optie {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.375rem 0.5rem; cursor: pointer;
  font-size: 0.875rem; color: var(--foreground);
  border-radius: calc(var(--radius) / 2);
  transition: background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-combo__optie[data-actief], .fp-combo__optie:hover { background: var(--muted); }
.fp-combo__optie[aria-disabled] { opacity: 0.5; pointer-events: none; }
.fp-combo__optie-tekst { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-combo__optie svg { flex-shrink: 0; color: var(--primary); }
.fp-combo__leeg { padding: 1.5rem 0; text-align: center; font-size: 0.875rem; color: var(--muted-foreground); }

/* ── Calendar (één datum) ───────────────────────────────────────────────── */

.fp-cal1 { display: inline-flex; flex-direction: column; gap: 0.5rem; padding: 0.75rem; color: var(--foreground); }
.fp-cal1__kop { display: flex; align-items: center; gap: 0.25rem; }
.fp-cal1__titel { flex: 1; display: flex; justify-content: center; align-items: center; gap: 0.375rem; font-size: 0.875rem; font-weight: 500; }
.fp-cal1__label { padding: 0 0.25rem; }
.fp-cal1__select {
  appearance: none; -webkit-appearance: none;
  font: inherit; font-size: 0.875rem; font-weight: 500; color: var(--foreground);
  background: var(--muted); border: 1px solid var(--border); border-radius: calc(var(--radius) / 2);
  padding: 0.25rem 1.5rem 0.25rem 0.5rem; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 0.8rem) 55%, calc(100% - 0.55rem) 55%;
  background-size: 0.25rem 0.25rem; background-repeat: no-repeat;
}
.fp-cal1__select:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 1px; }
.fp-cal1__pijl {
  display: flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem;
  appearance: none; border: 0; background: transparent; cursor: pointer;
  color: var(--muted-foreground); border-radius: calc(var(--radius) / 2);
  transition: background-color var(--motion-instant-duration) var(--motion-instant), color var(--motion-instant-duration) var(--motion-instant), transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-cal1__pijl:hover { background: var(--muted); color: var(--foreground); }
.fp-cal1__pijl[data-pressed] { transform: scale(0.92); }
.fp-cal1__pijl:disabled { opacity: 0.3; cursor: default; }
.fp-cal1__pijl:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-cal1__raster { display: grid; grid-template-columns: repeat(7, 2.25rem); gap: 0.125rem; }
.fp-cal1__dagnaam { display: flex; align-items: center; justify-content: center; height: 2rem; font-size: 0.75rem; font-weight: 500; color: var(--muted-foreground); }
.fp-cal1__dag {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem;
  appearance: none; border: 1px solid transparent; background: transparent; cursor: pointer;
  font: inherit; font-size: 0.875rem; color: var(--foreground);
  border-radius: calc(var(--radius) / 2);
  font-variant-numeric: tabular-nums;
  transition: background-color var(--motion-instant-duration) var(--motion-instant), color var(--motion-instant-duration) var(--motion-instant), transform var(--motion-instant-duration) var(--motion-instant);
}
.fp-cal1__dag:hover { background: var(--muted); }
.fp-cal1__dag[data-pressed] { transform: scale(0.94); }
.fp-cal1__dag[data-buiten] { color: var(--muted-foreground); opacity: 0.55; }
.fp-cal1__dag:disabled { opacity: 0.3; cursor: default; text-decoration: line-through; }
.fp-cal1__dag[data-gekozen] { background: var(--primary); color: var(--primary-foreground); }
/* Vandaag: een stip onder het cijfer; op de gekozen dag in de tegenkleur. */
.fp-cal1__dag[data-vandaag]::after { content: ""; position: absolute; bottom: 0.25rem; left: 50%; width: 3px; height: 3px; border-radius: 50%; background: var(--primary); transform: translateX(-50%); }
.fp-cal1__dag[data-vandaag][data-gekozen]::after { background: var(--primary-foreground); }
.fp-cal1__dag:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 1px; z-index: 1; }

/* ── Kbd ────────────────────────────────────────────────────────────────── */

.fp-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  height: 1.25rem; min-width: 1.25rem; padding: 0 0.25rem;
  font: inherit; font-size: 0.6875rem; font-weight: 500; line-height: 1;
  color: var(--muted-foreground); background: var(--muted);
  border: 1px solid var(--border); border-radius: calc(var(--radius) / 2);
  pointer-events: none; user-select: none;
}
.fp-kbd-groep { display: inline-flex; align-items: center; gap: 0.25rem; }

/* ── SearchField ────────────────────────────────────────────────────────── */

.fp-search { width: 100%; }
.fp-search--label-verborgen .fp-field__label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.fp-search .fp-input--met-trailing { padding-right: 4.25rem; }

/* ── TextRoll ───────────────────────────────────────────────────────────── */

.fp-roll { position: relative; display: inline-block; overflow: hidden; line-height: 0.85; padding-bottom: 0.08em; cursor: pointer; }
.fp-roll__laag { display: block; white-space: pre; }
.fp-roll__laag--onder { position: absolute; inset: 0; }
.fp-roll__letter { display: inline-block; will-change: transform; }

/* ── Menubar ────────────────────────────────────────────────────────────── */

.fp-mbar {
  display: inline-flex; align-items: center; gap: 0.25rem;
  height: 2.5rem; padding: 0.25rem;
  background: var(--background); color: var(--foreground);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.fp-mbar__popover .fp-popover { min-width: 12rem; padding: 0.25rem; }
.fp-mbar__trigger {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.375rem 0.75rem;
  appearance: none; border: 0; background: transparent; cursor: default;
  font: inherit; font-size: 0.875rem; font-weight: 500; color: var(--foreground);
  border-radius: calc(var(--radius) / 2); user-select: none;
  transition: background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-mbar__trigger:hover, .fp-mbar__trigger[data-open], .fp-mbar__trigger:focus-visible { background: var(--muted); outline: none; }
.fp-mbar__menu { list-style: none; margin: 0; padding: 0; }
.fp-mbar__item {
  position: relative; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.375rem 0.5rem; cursor: default; user-select: none;
  font-size: 0.875rem; border-radius: calc(var(--radius) / 2);
  transition: background-color var(--motion-instant-duration) var(--motion-instant);
}
.fp-mbar__item--vink { padding-left: 2rem; }
.fp-mbar__item:hover, .fp-mbar__item[data-actief] { background: var(--muted); }
.fp-mbar__item[aria-disabled] { opacity: 0.5; pointer-events: none; }
.fp-mbar__vink { position: absolute; left: 0.5rem; display: flex; width: 0.875rem; height: 0.875rem; align-items: center; justify-content: center; }
.fp-mbar__stip { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: currentColor; }
.fp-mbar__icoon { display: flex; width: 1rem; height: 1rem; flex-shrink: 0; color: var(--muted-foreground); }
.fp-mbar__label { flex: 1; }
.fp-mbar__sneltoets { margin-left: auto; font-size: 0.75rem; letter-spacing: 0.1em; color: var(--muted-foreground); }
.fp-mbar__scheiding { height: 1px; margin: 0.25rem -0.25rem; background: var(--border); }
.fp-mbar__kopje { padding: 0.375rem 0.5rem; font-size: 0.75rem; font-weight: 600; color: var(--muted-foreground); }

/* ── ReadingProgress ────────────────────────────────────────────────────── */

.fp-lees { display: flex; align-items: center; gap: 0.75rem; width: 100%; color: var(--foreground); }
.fp-lees__rail {
  flex: 1; min-width: 0; padding: 2px;
  background: var(--muted); border-radius: calc(var(--radius) / 2);
  box-shadow: inset 0 1px 2px color-mix(in srgb, var(--foreground) 7%, transparent);
}
.fp-lees__vul { display: block; height: 3px; width: 100%; transform-origin: left; background: var(--primary); border-radius: calc(var(--radius) / 4); }
/* Drie teksten in één vak: "nog 4 min" → "Einde · 6 min" verspringt niets. */
.fp-lees__tekst { display: grid; justify-items: end; flex-shrink: 0; font-size: 0.6875rem; font-variant-numeric: tabular-nums; }
.fp-lees__tekst > * { grid-area: 1 / 1; white-space: nowrap; }
.fp-lees__meet { visibility: hidden; display: flex; align-items: center; gap: 0.25rem; }
.fp-lees__over { color: var(--muted-foreground); }
.fp-lees__klaar { display: flex; align-items: center; gap: 0.25rem; color: var(--foreground); }
.fp-lees__vinkvak { display: inline-block; width: 0.75rem; height: 0.75rem; flex-shrink: 0; }

/* ── PhoneMockup ────────────────────────────────────────────────────────── */

.fp-phone {
  --fp-phone-frame: var(--foreground);
  --fp-phone-screen: var(--background);
  display: inline-block; box-sizing: border-box;
  /* De schaal is een transform; de layout-maat schaalt mee zodat er geen leeg vlak overblijft. */
  width: calc(var(--fp-phone-w) * var(--fp-phone-scale, 1)); height: calc(var(--fp-phone-h) * var(--fp-phone-scale, 1));
}
.fp-phone__lijst { transform: scale(var(--fp-phone-scale, 1)); transform-origin: top left; }
.fp-phone__lijst {
  position: relative; box-sizing: border-box; overflow: hidden;
  width: var(--fp-phone-w); height: var(--fp-phone-h); padding: var(--fp-phone-bezel);
  border-radius: calc(var(--fp-phone-r) + var(--fp-phone-bezel));
  background: linear-gradient(135deg, color-mix(in srgb, var(--fp-phone-frame) 92%, var(--background)) 0%, var(--fp-phone-frame) 40%, color-mix(in srgb, var(--fp-phone-frame) 86%, var(--background)) 100%);
}
.fp-phone--schaduw .fp-phone__lijst { box-shadow: var(--shadow-overlay); }
.fp-phone__scherm {
  position: relative; overflow: hidden; width: 100%; height: 100%;
  border-radius: var(--fp-phone-r);
  background: var(--fp-phone-screen);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fp-phone-frame) 6%, transparent), inset 0 10px 20px color-mix(in srgb, var(--fp-phone-frame) 25%, transparent);
}
.fp-phone__wallpaper { position: absolute; inset: 0; background-position: center; background-repeat: no-repeat; }
.fp-phone__uitsnede {
  position: absolute; left: 50%; transform: translateX(-50%); z-index: 2;
  width: var(--fp-phone-cut-w); height: var(--fp-phone-cut-h); border-radius: var(--fp-phone-cut-r);
  background: var(--fp-phone-frame);
}
.fp-phone__uitsnede--island { top: 12px; }
.fp-phone__uitsnede--notch { top: 8px; border-top-left-radius: 0; border-top-right-radius: 0; }
.fp-phone__inhoud { position: absolute; inset: var(--fp-phone-top) 0 var(--fp-phone-bottom) 0; overflow: hidden; z-index: 1; display: flex; flex-direction: column; }
.fp-phone__thuis {
  position: absolute; bottom: 8px; left: 50%; transform: translateX(-50%); z-index: 3;
  width: 34%; max-width: 140px; height: 5px; border-radius: 999px;
  background: color-mix(in srgb, var(--foreground) 60%, transparent); pointer-events: none;
}

/* ── HoverExpandGallery ─────────────────────────────────────────────────── */

.fp-hgal { display: flex; align-items: stretch; justify-content: center; gap: 0.25rem; width: 100%; }
.fp-hgal__strook {
  position: relative; flex: 1 1 0; min-width: 2.5rem; overflow: hidden;
  appearance: none; border: 0; padding: 0; cursor: pointer;
  border-radius: calc(var(--radius) * 2); background: var(--muted);
}
.fp-hgal__strook[data-open] { flex: 6 1 0; }
.fp-hgal__strook:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: 2px; }
.fp-hgal__beeld { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fp-hgal__waas {
  position: absolute; inset: 0; display: flex; align-items: flex-end; justify-content: flex-end; padding: 1rem;
  background: linear-gradient(to top, color-mix(in srgb, var(--background) 60%, transparent), transparent 50%);
}
.fp-hgal__onderschrift { font-size: 0.75rem; color: color-mix(in srgb, var(--foreground) 70%, transparent); }

/* ── HoverPreviewList ───────────────────────────────────────────────────── */

.fp-hpl { position: relative; width: 100%; overflow: hidden; color: var(--foreground); background: var(--card); }
.fp-hpl__lijst { position: relative; z-index: 3; list-style: none; margin: 0; padding: 0; }
.fp-hpl__rij {
  display: grid; grid-template-columns: 1fr 1fr 2fr; gap: 1rem;
  padding: 0.75rem 1.5rem; cursor: default;
  transition: color var(--motion-default-duration) var(--motion-default);
}
.fp-hpl__rij[data-actief] { color: var(--background); }
.fp-hpl__rij[role="button"] { cursor: pointer; }
.fp-hpl__rij:focus-visible { outline: 2px solid var(--ring, var(--info)); outline-offset: -2px; }
.fp-hpl__cel { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* De balk onder de tekst: tekstkleur, schuift met y; hoogte is de gemeten rijhoogte. */
.fp-hpl__balk { position: absolute; left: 0; right: 0; top: 0; z-index: 1; height: var(--fp-hpl-rij, 0px); background: var(--foreground); pointer-events: none; }
.fp-hpl__beelden { position: absolute; inset: 0; z-index: 2; pointer-events: none; mix-blend-mode: difference; }
.fp-hpl__beeld {
  position: absolute; left: 35%; top: 50%; transform: translateY(-50%);
  width: calc(19.5rem * var(--fp-hpl-schaal, 1)); height: calc(22.5rem * var(--fp-hpl-schaal, 1));
  will-change: clip-path, opacity;
}
.fp-hpl__beeld img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Touch: gewone lijst met beeld ernaast. */
.fp-hpl--touch { list-style: none; margin: 0; padding: 0; }
.fp-hpl__kaart { display: flex; border-bottom: 1px solid var(--border); }
.fp-hpl__kaart-tekst { display: flex; flex-direction: column; gap: 0.25rem; width: 50%; padding: 1rem; }
.fp-hpl__kaart .fp-hpl__titel { margin: 0; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.875rem; }
.fp-hpl__kaart .fp-hpl__meta { margin: 0; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.75rem; color: var(--muted-foreground); }
.fp-hpl__kaart .fp-hpl__tekst { margin: 0; font-size: 0.75rem; line-height: 1.6; color: var(--muted-foreground); }
.fp-hpl__kaart-beeld { width: 50%; aspect-ratio: 3 / 4; object-fit: cover; }

/* ── InfiniteSlider ─────────────────────────────────────────────────────── */

.fp-slider { position: relative; width: 100%; overflow: hidden; background: var(--background); color: var(--foreground); touch-action: none; }
.fp-slider__reeks { position: absolute; inset: 0; }
.fp-slider__kaart { position: absolute; inset: 0 auto auto 0; width: 100%; height: 100%; overflow: hidden; will-change: transform; }
.fp-slider__kaart img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transform: scale(1.5); will-change: transform; }
.fp-slider__minimap { position: absolute; right: 1.5rem; top: 50%; transform: translateY(-50%); display: none; gap: 1rem; height: 250px; }
@media (min-width: 900px) { .fp-slider__minimap { display: flex; } }
.fp-slider__minimap-beelden { position: relative; width: 160px; height: 250px; overflow: hidden; border-radius: var(--radius); }
.fp-slider__minimap-beeld { position: absolute; inset: 0 auto auto 0; width: 100%; height: 250px; overflow: hidden; will-change: transform; }
.fp-slider__minimap-beeld img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transform: scale(1.5); will-change: transform; }
.fp-slider__minimap-info { position: relative; width: 200px; height: 250px; overflow: hidden; }
.fp-slider__info { position: absolute; inset: 0 auto auto 0; width: 100%; height: 250px; display: flex; flex-direction: column; justify-content: center; gap: 0.5rem; will-change: transform; }
.fp-slider__info-rij { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; color: color-mix(in srgb, var(--foreground) 80%, transparent); }
.fp-slider__info-rij:first-child { font-weight: 600; color: var(--foreground); }