/* ==========================================================================
   Fonts
   National 2 is the base face for all running text. The PP display faces are
   used only for the animated header ampersand and the decorative ampersands
   over the related-work gallery, so each ships a single weight.
   ========================================================================== */
@font-face { font-family: 'National 2'; src: url('../fonts/National2-Light.otf') format('opentype'); font-weight: 300; font-display: swap; }
@font-face { font-family: 'National 2'; src: url('../fonts/National2-Regular.otf') format('opentype'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'National 2'; src: url('../fonts/National2-Medium.otf') format('opentype'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'National 2'; src: url('../fonts/National2-Bold.otf') format('opentype'); font-weight: 700; font-display: swap; }

@font-face { font-family: 'PP Cirka'; src: url('../fonts/PPCirka-Bold.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'PP Editorial New'; src: url('../fonts/PPEditorialNew-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'PP Eiko'; src: url('../fonts/PPEiko-Black.woff2') format('woff2'); font-weight: 900; font-display: swap; }
@font-face { font-family: 'PP Fuji'; src: url('../fonts/PPFuji-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'PP Gatwick'; src: url('../fonts/PPGatwick-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'PP Neue Montreal'; src: url('../fonts/PPNeueMontreal-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'PP Rader'; src: url('../fonts/PPRader-Medium.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'PP Charlevoix'; src: url('../fonts/PPCharlevoix-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }

/* ==========================================================================
   Design tokens
   Pulled straight from the Figma variables (mondrian-blue, mondrian-yellow,
   mondrian-red, hey-green, cinza) plus the pink used on the footer arrow.
   ========================================================================== */
:root {
  --rp-black: #000000;
  --rp-white: #ffffff;
  --rp-gray: #909090;
  --rp-blue: #004bf4;
  --rp-yellow: #ffbf01;
  --rp-red: #ff0700;
  --rp-green: #008858;
  --rp-pink: #f184d4;

  --rp-font-display: 'National 2', 'Helvetica Neue', Arial, sans-serif;
  --rp-font-mark: 'PP Cirka', Georgia, serif;

  /* ---- Type styles (site-wide — reuse these on every new page) ----------
     Reverted 2026-07-09 (2nd pass) to the raw Figma spec, anchored to the
     1920px artboard:
     title        National 2 Medium  58/58 (project title: mixed case; "& much more": lowercase)
     body-lg      National 2 Regular 44/48 (project text — mixed case)
     to-top       National 2 Regular 44/44 (back to the top — lowercase)
     label        National 2 Regular 20/24 (info rows + CREDITS label — ALL CAPS)
     credit-role  National 2 Medium  20/30 (mixed case)
     credit-name  National 2 Regular 20/30 (mixed case)
     card-title   National 2 Medium  24/28 (gallery card title — mixed case)
     card-tags    National 2 Regular 24/28 (gallery card areas — lowercase)

     Why anchor to 1920 and not a real device width: Rodrigo's reference
     screenshot is Figma zoomed-to-fit-width, i.e. the 1920 artboard shrunk
     by (window width ÷ 1920). Anchoring our vw scale to that same 1920
     figure means our page always renders text at exactly the same
     proportion Figma shows, AT ANY window width — a fixed 1512 (or any
     other) reference can only match at one specific width. A previous pass
     anchored to 1512 (MacBook Pro 14" logical width) and shrunk the spec to
     hit a flat 30px there; that was solving the wrong problem (an absolute
     target) instead of a proportional match to Figma, so it read smaller
     than the reference screenshot. Don't re-introduce a device-width anchor
     without re-deriving this.
     vw value = spec px ÷ 19.2. Mobile floors are ~62% of spec, matching the
     original ratio Rodrigo saw as comfortable on the 1512 pass.
  ------------------------------------------------------------------------ */
  --rp-type-title:       500 clamp(36px, 3.0208vw, 58px)/1     var(--rp-font-display);
  --rp-type-body-lg:     400 clamp(26px, 2.2917vw, 44px)/1.091 var(--rp-font-display);
  --rp-type-totop:       400 clamp(26px, 2.2917vw, 44px)/1     var(--rp-font-display);
  --rp-type-label:       400 clamp(16px, 1.0417vw, 20px)/1.2   var(--rp-font-display);
  --rp-type-credit-role: 500 clamp(16px, 1.0417vw, 20px)/1.5   var(--rp-font-display);
  --rp-type-credit-name: 400 clamp(16px, 1.0417vw, 20px)/1.5   var(--rp-font-display);
  --rp-type-card-title:  500 clamp(20px, 1.25vw, 24px)/1.167   var(--rp-font-display);
  --rp-type-card-tags:   400 clamp(20px, 1.25vw, 24px)/1.167   var(--rp-font-display);

  --rp-radius: 20px;
  --rp-gap: 14px;
  --rp-page-margin: 14px;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* the decorative ampersands hang past both page edges; clip (not hidden)
     so position:sticky on the header keeps working */
  overflow-x: clip;
}

body {
  background: var(--rp-black);
  color: var(--rp-white);
  font-family: var(--rp-font-display);
  margin: 0;
  /* National 2 renders noticeably heavier without this on macOS/Chrome */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

.rp-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 var(--rp-page-margin);
}

/* ==========================================================================
   Header
   ========================================================================== */
.rp-header {
  /* full-bleed: this is a direct child of <body> (NOT of the padded
     .rp-page wrapper — moved there deliberately), so a plain width:100%
     already spans the entire viewport edge-to-edge with zero extra work.
     An earlier version tried to keep the header inside .rp-page and
     "break out" of its 14px side padding via width:100vw + a
     margin/translate trick; that fought .rp-page's own
     `display:flex; align-items:center` centering in confusing ways (the
     asymmetric margin got centered as part of the margin box, throwing
     the math off). Moving the element outside the padded container
     entirely is simpler and avoids the whole problem. */
  position: sticky;
  top: 0;
  z-index: 20;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  /* Horizontal padding matches the page's own 14px base margin (was 28px —
     double the body content's inset below it, so the logo/menu sat further
     from the edge than "rodrigo."'s own column beneath it). */
  padding: 24px 14px;
  background: var(--rp-black);
  transition: transform 0.35s ease;
}

.rp-header--hidden {
  transform: translateY(-115%);
}

.rp-header__intro {
  display: flex;
  align-items: center;
  /* was gap:7px; a flat 10px-closer request went past 0, so the gap moved
     onto the wordmark itself as a negative margin (7px - 10px = -3px). */
  gap: 0;
}

.rp-ampersand {
  /* Now backed by hand-drawn SVG outlines (Rodrigo's Illustrator export,
     assets/img/ampersands/*.svg) instead of live text cycling through PP
     display faces — that approach kept fighting font-metric measurement
     across browsers (Range.getBoundingClientRect() doesn't expose true
     glyph ink, only line-box metrics) and never matched his eye. All 5
     SVGs share one viewBox (0 0 55 55) from the same Illustrator artboard,
     positioned by hand against the wordmark, so alignment is solved once
     here in CSS — no per-shape JS math needed.

     Horizontal: a fixed-width slot with the glyph RIGHT-aligned (flex
     justify-content:flex-end on a wider-than-content box). Fixed width
     stops "rodrigo." shifting when a differently-shaped glyph swaps in;
     right alignment keeps the gap to "rodrigo." constant regardless of
     each glyph's own width. Leftover slack falls on the left, against the
     page edge, invisibly.

     Color is set as `fill` directly on the <path> in main.js (not via this
     element's `color` + SVG currentColor inheritance) — the transition
     lives on .rp-ampersand__svg path below. */
  --amp-base-size: clamp(30px, 2.6042vw, 50px);
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  width: calc(var(--amp-base-size) * 1.3);
}

.rp-ampersand__svg {
  width: var(--amp-base-size);
  height: var(--amp-base-size);
  display: block;
  overflow: visible;
  /* Overall optical nudge, applied once to all 10 shapes (not per-shape —
     they're already hand-aligned to each other in Illustrator, this just
     shifts that whole aligned group down slightly against the wordmark). */
  transform: translateY(2px);
}
.rp-ampersand__svg path {
  transition: fill 0.3s ease;
}

.rp-wordmark {
  /* National 2 Medium, spec 40px at 1920w. Stepped breakpoints, not
     continuous vw scaling like the rest of the header — Rodrigo asked for
     discrete size jumps here specifically, so the wordmark/menu hold
     steady within a range instead of visibly resizing while the window is
     dragged. See the breakpoint tiers at the bottom of this file. */
  font-weight: 500;
  font-size: 24px;
  color: var(--rp-white);
  display: inline-block;
  text-box: trim-both cap alphabetic;
  margin-left: -3px;
}

.rp-menu__list {
  display: flex;
  align-items: center;
  gap: 28px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.rp-menu__list a {
  /* National 2 Regular, spec 40px at 1920w. Stepped breakpoints — see
     .rp-wordmark above and the tiers at the bottom of this file; the two
     stay in lockstep so nav text and the wordmark always match size. */
  position: relative;
  display: inline-block;
  font-weight: 400;
  font-size: 24px;
  color: var(--rp-white);
  padding-bottom: 0.05em;
  transition: color 0.25s ease;
}

/* Wavy underline lives on ::after (not the link's own background) so its
   reveal can be animated independently of the text — see main.js, which
   drives an Element.animate() clip-path sweep on hover/hover-out (a plain
   CSS transition can't do this: entering sweeps in from the right edge,
   exiting sweeps out toward the right, i.e. two DIFFERENT end shapes for
   the same resting state, which a single transition pair can't express).

   The actual wave artwork (background-image/-size below) is generated and
   set by main.js, NOT hardcoded here, and NOT a `repeat-x` tile. Reasons:
   1) a repeat-x tile has no start/end by definition, so it can never show
      the rounded pill caps Rodrigo drew for the strip's two ends
      (assets/img/wave-underline-reference.svg);
   2) baking ONE fixed hump-count strip and stretching it to 100% width
      (an earlier pass) forces the SAME peak count on every word regardless
      of length — wrong, a longer word should show more peaks, not the same
      peaks stretched wider.
   main.js measures each link's actual rendered width and builds a
   bespoke SVG with exactly the right number of capped humps for that
   width (~6 peaks for "work" specifically), writing it into --wave-bg/
   --wave-w/--wave-h below at 1:1 unit:px scale — so peak count tracks word
   length and the caps are always real, never stretched. */
.rp-menu__list a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--wave-h, 0.17em);
  background-image: var(--wave-bg);
  background-repeat: no-repeat;
  background-position: left bottom;
  background-size: var(--wave-w, 100%) var(--wave-h, 0.17em);
  clip-path: inset(0 100% 0 0);
  pointer-events: none;
}

/* Hover text colors — three different accents so each item feels distinct,
   matching the wavy-underline "active" treatment already used on Work.
   (The wave's OWN fill color is set per-link in main.js via
   data-wave-color on the <a>, kept in lockstep with these.) */
.rp-menu__list li:nth-child(1) a:hover { color: var(--rp-red); }
.rp-menu__list li:nth-child(2) a:hover,
.rp-menu__list li.current-menu-item a,
.rp-menu__list li.current-menu-parent a,
.rp-menu__list li.current-menu-ancestor a { color: var(--rp-yellow); }
.rp-menu__list li:nth-child(3) a:hover { color: var(--rp-green); }

/* Active item (Work): wave stays permanently visible, no hover animation —
   the JS skips wiring mouseenter/mouseleave for .current-menu-item links. */
.rp-menu__list li.current-menu-item a::after,
.rp-menu__list li.current-menu-parent a::after,
.rp-menu__list li.current-menu-ancestor a::after {
  clip-path: inset(0 0 0 0);
}

/* ==========================================================================
   Content shell
   ========================================================================== */
.rp-content {
  width: 100%;
  max-width: 1892px;
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding-top: 0px;
}

/* Hero */
.rp-hero {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--rp-radius);
  overflow: hidden;
}
.rp-hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Info card — same 4-column grid as .rp-credits/.rp-related, so the
   description text is hard-capped to the right two columns and can never
   run wider than that regardless of copy length or font size. */
.rp-info {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  /* the whole info card sits 14px further in than the page margin. No
     bottom padding here — .rp-content's own 28px gap already spaces this
     section from the gallery below, same as every other section-to-section
     transition on the page; adding padding-bottom here on top of that gap
     was doubling it to 56px, out of proportion with the rest of the page. */
  padding: 0 14px;
}

.rp-info__meta {
  grid-column: 1 / 3;
  display: flex;
  flex-direction: column;
  /* title pinned to the top, YEAR/roles/awards pinned to the bottom of the
     box so they end flush with the description column, as in the Figma */
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
}

.rp-info__title {
  font: var(--rp-type-title);
  margin: 0;
  padding-bottom: 14px;
}

.rp-info__list {
  display: flex;
  flex-direction: column;
  /* the 3 rows (YEAR / roles / awards) get half the card's 14px base
     unit — a tighter sub-rhythm between these rows specifically */
  gap: 7px;
  font: var(--rp-type-label);
  text-transform: uppercase;
}

.rp-info__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.rp-tag { font-weight: 400; white-space: nowrap; }
.rp-tag--red { color: var(--rp-red); }
.rp-tag--blue { color: var(--rp-blue); }
.rp-tag--yellow { color: var(--rp-yellow); }
.rp-info__value { color: var(--rp-white); }

.rp-info__description {
  grid-column: 3 / 5;
  min-width: 0;
}
.rp-info__description p {
  font: var(--rp-type-body-lg);
  margin: 0;
  overflow-wrap: break-word;
}

/* ==========================================================================
   Gallery (auto wide/square based on the uploaded image's aspect ratio)
   ========================================================================== */
.rp-gallery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--rp-gap);
  width: 100%;
}

.rp-gallery__item {
  border-radius: var(--rp-radius);
  overflow: hidden;
}
.rp-gallery__item img,
.rp-gallery__item video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rp-gallery__item--wide {
  flex: 1 1 100%;
  aspect-ratio: 16 / 9;
}

.rp-gallery__item--square {
  flex: 1 1 calc(50% - var(--rp-gap) / 2);
  aspect-ratio: 1 / 1;
}

/* ==========================================================================
   Credits
   ========================================================================== */
.rp-credits {
  /* same 4-column rhythm as the related-work gallery; the credits text
     occupies the second column */
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  padding-bottom: 40px;
}
.rp-credits__inner {
  grid-column: 2 / 3;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.rp-credits__label {
  color: var(--rp-green);
  font: var(--rp-type-label);
  text-transform: uppercase;
  margin: 0 0 6px;
}
.rp-credits__line {
  margin: 0 0 14px;
  font: var(--rp-type-credit-name);
}
.rp-credits__role { font: var(--rp-type-credit-role); }
.rp-credits__names { color: var(--rp-white); }

/* ==========================================================================
   Related work grid
   ========================================================================== */
.rp-related {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  padding: 14px 0;
  width: 100%;
}

/* Big white ampersands straddling the top edge of the related-work gallery,
   each set in a different PP display face — mirrors the Figma composition
   where they hang past both page edges.

   Positioning: the overlay shares the exact grid (columns + gap) of the
   cards below it, so each ampersand is placed by GRID LINE, not a %
   left-offset — % drifted out of place because the 28px gap doesn't scale
   with width the way a percentage does. An ampersand centered on the
   boundary between column N and N+1 spans grid-column N/(N+2) (i.e. both
   flanking columns) with justify-self:center — since both columns are
   equal width, the midpoint of that span always lands exactly on the
   shared line between them, regardless of viewport width. The two edge
   ampersands span just the outer column with justify-self:start/end, then
   shift out by 50% of their own width so their *center* (not edge) sits on
   the page edge, hanging half off it like the Figma composition.

   Sizing: uses the ORIGINAL Figma font-sizes for these 5 glyphs directly
   (from the source design: Räder 139.446px, Eiko Italic Medium 136.45px,
   Cirka Bold 157.48px, Gatwick Regular 136.054px, Casa Regular 143.25px —
   Casa isn't licensed so Editorial New stands in for it here). An earlier
   pass tried to equalize by measuring each face's rendered ink-height in
   the browser instead (Range.getBoundingClientRect()) and back-solving a
   per-face factor from that — that made Räder's font-size SMALLER than
   Eiko's, which is backwards: in the real design Räder (139.45) is
   slightly LARGER than Eiko (136.45). Trust the designer's own relative
   sizing over a browser ink-height measurement. --amp-size is Eiko's
   font-size (target 100px at Eiko's own scale); the other four are
   `--amp-size * (their Figma px ÷ Eiko's Figma px)`, i.e. the exact same
   ratio to each other as in the original file. Fixed 100px-equivalent
   scale on any screen — this is a decorative flourish, not body copy, so
   unlike the type scale it does NOT scale with viewport/vw. */
.rp-related__amps {
  position: absolute;
  top: 14px; /* the gallery images start below the section's own padding */
  left: 0;
  right: 0;
  height: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  pointer-events: none;
  z-index: 2;
  color: var(--rp-white);
  --amp-size: 100px;
}
.rp-related__amp {
  /* every glyph must share row 1 explicitly — their grid-column spans
     overlap each other on purpose (see note above), and without a fixed
     grid-row, auto-placement pushes each overlapping item to its own new
     row instead of layering them, producing a staircase/diagonal instead
     of one straddling band. align-items:start (not the grid default
     stretch) keeps each item's pre-transform top edge at the shared row
     line, so translateY(-50%) centers every glyph on the same line
     regardless of its own font-size. */
  grid-row: 1;
  align-self: start;
  line-height: 1;
  white-space: nowrap;
  transform: translateY(-50%);
}
.rp-related__amp:nth-child(1) {
  grid-column: 1 / 2;
  justify-self: start;
  /* no non-uniform scaleX — stretching only one axis distorts the glyph.
     font-size alone scales both axes together, undistorted. */
  transform: translate(-50%, -50%);
  font-family: 'PP Rader', serif;   font-weight: 500; font-size: calc(var(--amp-size) * 1.022);
}
.rp-related__amp:nth-child(2) {
  grid-column: 1 / 3;
  justify-self: center;
  font-family: 'PP Eiko', serif;    font-weight: 900; font-style: italic; font-size: calc(var(--amp-size) * 1.0);
}
.rp-related__amp:nth-child(3) {
  grid-column: 2 / 4;
  justify-self: center;
  font-family: 'PP Cirka', serif;   font-weight: 700; font-size: calc(var(--amp-size) * 1.154);
}
.rp-related__amp:nth-child(4) {
  grid-column: 3 / 5;
  justify-self: center;
  font-family: 'PP Gatwick', sans-serif; font-weight: 400; font-size: calc(var(--amp-size) * 0.997);
}
.rp-related__amp:nth-child(5) {
  grid-column: 4 / 5;
  justify-self: end;
  transform: translate(50%, -50%);
  font-family: 'PP Editorial New', serif; font-weight: 400; font-size: calc(var(--amp-size) * 1.050);
}
.rp-related__card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
.rp-related__thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--rp-radius);
  overflow: hidden;
}
.rp-related__thumb img,
.rp-related__thumb video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.rp-related__title {
  font: var(--rp-type-card-title);
  margin: 0;
  color: var(--rp-white);
}
.rp-related__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0 14px;
  color: var(--rp-gray);
  font: var(--rp-type-card-tags);
  text-transform: lowercase;
  margin: 0;
}
.rp-related__tags span::after {
  content: '';
}

/* ==========================================================================
   Footer
   ========================================================================== */
.rp-footer {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  padding: 40px 0 14px;
}
.rp-footer__title {
  font: var(--rp-type-title);
  text-transform: lowercase;
  margin: 0;
}
.rp-footer__totop {
  font: var(--rp-type-totop);
  text-transform: lowercase;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.rp-footer__arrow {
  display: inline-block;
  color: var(--rp-pink);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.rp-footer__totop:hover .rp-footer__arrow {
  transform: rotate(-90deg);
}

/* ==========================================================================
   Responsive
   ========================================================================== */

/* Wordmark + nav link stepped size breakpoints (base rule above is the
   smallest tier, 24px). Discrete jumps instead of continuous vw scaling —
   requested specifically for these two elements so they hold steady within
   a range rather than visibly resizing while the window is dragged. */
@media (min-width: 900px) {
  .rp-wordmark,
  .rp-menu__list a { font-size: 28px; }
}
@media (min-width: 1200px) {
  .rp-wordmark,
  .rp-menu__list a { font-size: 34px; }
}
@media (min-width: 1600px) {
  .rp-wordmark,
  .rp-menu__list a { font-size: 40px; }
}

@media (max-width: 900px) {
  .rp-header { padding: 16px 14px; }
  .rp-menu__list { gap: 16px; }
  .rp-gallery__item--square { flex-basis: 100%; aspect-ratio: 1 / 1; }
  .rp-info { display: block; }
  .rp-info__meta { margin-bottom: 20px; }
  .rp-credits { display: block; }
  .rp-footer { align-items: flex-start; flex-direction: column; }

  /* Related-work gallery drops to 2 columns / 2 rows. That leaves only 3
     line boundaries (left edge, middle, right edge) instead of 5, so two of
     the five ampersands are hidden and the remaining three are re-pinned to
     the new 2-column grid the same line-based way as desktop. */
  .rp-related,
  .rp-related__amps { grid-template-columns: repeat(2, 1fr); }
  .rp-related__amp:nth-child(2),
  .rp-related__amp:nth-child(4) { display: none; }
  .rp-related__amp:nth-child(3) {
    grid-column: 1 / 3;
    justify-self: center;
  }
  .rp-related__amp:nth-child(5) { grid-column: 2 / 3; }
}

@media (prefers-reduced-motion: reduce) {
  .rp-header,
  .rp-ampersand__svg path,
  .rp-footer__arrow {
    transition: none;
  }
}

/* ==========================================================================
   Custom cursor
   A plain white 8px dot that follows the pointer, growing slightly and
   picking a random brand color on hover over interactive elements.
   mix-blend-mode: difference keeps the idle dot visible on any background
   (white inverts to black over light bg, stays white over dark bg) — turned
   off on hover so the chosen brand color renders true instead of blended.
   `cursor: none` needs !important on the interactive selectors because
   Safari/Chrome apply their own `:any-link`-style pointer cursor to links
   directly (not just inherited from body), which otherwise wins over the
   inherited `none`.
   ========================================================================== */
html, body { cursor: none; }

a, button, [role="button"], input, textarea, select, label {
  cursor: none !important;
}

.rp-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rp-white);
  pointer-events: none;
  z-index: 9999;
  mix-blend-mode: difference;
  transform: translate3d(-50%, -50%, 0);
  opacity: 0;
  transition: width 0.15s ease, height 0.15s ease, background-color 0.15s ease, opacity 0.15s ease;
  will-change: transform;
}

.rp-cursor--hover {
  width: 12px;
  height: 12px;
  mix-blend-mode: normal;
}

@media (hover: none), (pointer: coarse) {
  .rp-cursor { display: none; }
  html, body { cursor: auto; }
  a, button, [role="button"], input, textarea, select, label { cursor: auto !important; }
}
