@font-face {
  font-family: 'TWK Lausanne';
  src: url('../assets/fonts/TWKLausanne-300.woff2') format('woff2'), url('../assets/fonts/TWKLausanne-300.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'TWK Lausanne';
  src: url('../assets/fonts/TWKLausanne-350.woff2') format('woff2'), url('../assets/fonts/TWKLausanne-350.ttf') format('truetype');
  font-weight: 350;
  font-style: normal;
  font-display: swap;
}

/* 400 has its own name, so bold text that now falls back to 350 stays as it is. Only the case study learnings use it (case.css). */
@font-face {
  font-family: 'TWK Lausanne 400';
  src: url('../assets/fonts/TWKLausanne-400.woff2') format('woff2'), url('../assets/fonts/TWKLausanne-400.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* The page is light, but the window's own scrollbar follows the browser: dark when Chrome or the system is in dark mode.
   Chrome themes the viewport scrollbar from the root's color-scheme (https://web.dev/articles/color-scheme), so the
   root takes both, and the body sets light again, so inputs, the panels' own scrollbars and all else in the page stay
   light. The body's background still fills the window behind it. */
:root {
  color-scheme: light dark;
}

* {
  box-sizing: border-box;
}

/* Selected text: --highlight behind it, the text as it is. */
::selection {
  background-color: var(--highlight);
  color: var(--highlight-ink);
}

html,
body {
  height: 100%;
  margin: 0;
}

/* The page scrolls only to show the goodbye (footer.js), and stops dead at either end. Sideways it never overscrolls,
   so a two-finger swipe never sends Chrome back or forward a page; swipe.js turns it into a step side to side. */
html {
  overscroll-behavior-x: none;
  overscroll-behavior-y: none;
}


body {
  color-scheme: light;
  display: flex;
  flex-direction: column;
  min-height: calc(100dvh + var(--reveal, 0px)); /* the first screen, then room to scroll the card up (footer.js) */
  background: var(--page);
  color: var(--ink);
  font: 300 var(--text-size)/var(--text-leading) 'TWK Lausanne', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Grain (--grain in tokens.css). One fixed layer over everything, the case studies and panels too, that clicks pass through. */

/* While the grain is on, the canvas takes Rachel's page colour (--grain-bg), as her site has it under the same grain,
   and the page behind it takes --grain-page, a grey, so the canvas keeps its depth. The head script sets .grain-bg
   whenever --grain is 1. */
.grain-bg {
  --page: var(--grain-page);
  --card: var(--grain-bg);
}

body::after {
  content: '';
  position: fixed;
  z-index: 9999;
  inset: 0;
  opacity: calc(var(--grain) * var(--grain-opacity));
  mix-blend-mode: var(--grain-blend);
  background: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0 / var(--grain-size) repeat;
  pointer-events: none;
}

@media (prefers-reduced-transparency: reduce) {
  body::after {
    opacity: calc(var(--grain) * .025);
  }
}

button {
  margin: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--motion-fast) var(--motion-ease-out), transform var(--motion-fast) var(--motion-ease-out);
}

button:focus-visible {
  outline: 1px solid var(--mute);
  outline-offset: 2px;
}

/* No focus ring while the mouse or a finger was last used (focus.js); Tab brings them back. */
html.pointing :focus-visible {
  outline: none !important;
}

.links button:active {
  transform: scale(var(--press-scale));
}

/* Track. One card that stays put until you scroll past the end of a panel; then the page carries it up off the goodbye.
   Figma draws the line outside the box, so a shadow draws it here and offsets stay true.
   It shows one panel at a time; track.js fades between them when a tab is pressed. Nothing scrolls sideways. */
.track {
  position: relative;
  flex: 1;
  min-height: var(--card-min);
  margin: var(--card-top) var(--card-side) 0;
}

.card {
  overflow: clip;
  border-radius: var(--card-radius);
  background: var(--card);
  box-shadow: 0 0 0 var(--card-line) var(--line);
}

/* While a case study is open, a sheet of the card's own colour covers its content (case.js sets --case-white). */
.track::after {
  content: '';
  position: absolute;
  z-index: 10;
  inset: 0;
  background: var(--card);
  opacity: var(--case-white, 0);
  pointer-events: none;
}

/* Each panel fills the card and scrolls down inside itself. Past its end the same scroll carries on into the page, which
   moves the card up to show the goodbye behind it. footer.js hands it over, so a panel neither bounces at its end nor
   passes the scroll on by itself. On touch the browser hands it over (no wheel there). */
.panel {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior-y: none;
  scrollbar-width: none;
}

@media (pointer: coarse) {
  .panel {
    overscroll-behavior-y: auto;
  }
}

.panel::-webkit-scrollbar {
  display: none;
}

.panel[hidden] {
  display: none;
}

/* The orchard's first screen fills the card, and clips anything that runs past its edges. */
.hero {
  position: relative;
  height: 100%;
  overflow: clip;
}

/* A panel takes focus when a click lands in it, so the keys scroll it. It needs no ring. */
.panel:focus {
  outline: none;
}

.hero p,
.hero h1,
.hero .down {
  position: absolute;
  margin: 0;
  font: inherit;
  white-space: nowrap;
  left: 50%;
  translate: -50% 0;
}

.status {
  top: var(--status-top);
  color: var(--mute);
}

/* The autumn rock scene: 364 by 213 art pixels at --scene-scale, centred. Whole sizes, or halves on a 2x screen, make each
   art pixel a whole number of screen pixels; sizes between them make some a screen pixel wider (wind.js caps the size). Across, it is the whole picture that centres,
   the side pieces too: --scene-shift (wind.js, in art pixels) moves the box by how far their middle sits right of the
   rock scene's own. Its corner is rounded to a whole pixel, so the pixel art never lands between pixels and blurs. */
.scene {
  position: absolute;
  top: round(down, calc(50% + var(--scene-y) - 106.5px * var(--scene-scale)), 1px);
  left: round(down, calc(50% + var(--scene-x) - (182px + var(--scene-shift, 0) * 1px) * var(--scene-scale)), 1px);
  width: calc(364px * var(--scene-scale));
  height: calc(213px * var(--scene-scale));
  pointer-events: none;
}

.scene img,
.scene .shadow {
  position: absolute;
}

.scene img {
  left: calc(var(--x) * var(--scene-scale) * 1px);
  top: calc(var(--y) * var(--scene-scale) * 1px);
  width: calc(var(--w) * var(--scene-scale) * 1px);
  height: calc(var(--h) * var(--scene-scale) * 1px);
  max-width: none;
  image-rendering: pixelated;
}

/* The flat grey shadow under the raccoon, measured from the flat version: centre 84.4, 196, radii 72.3 by 16.5. */
.scene .shadow {
  left: calc(12.1px * var(--scene-scale));
  top: calc(179.5px * var(--scene-scale));
  width: calc(144.6px * var(--scene-scale));
  height: calc(33px * var(--scene-scale));
  border-radius: 50%;
  background: var(--scene-shadow);
}

.down {
  top: calc(100% - var(--down-bottom));
  opacity: var(--down-fade);
}

/* Bar */
.bar {
  position: sticky; /* pinned at the bottom while the card scrolls up past it */
  bottom: var(--bar-bottom);
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  height: var(--bar-height);
  margin: var(--bar-top) var(--bar-side) var(--bar-bottom);
  font-size: var(--bar-size);
  line-height: var(--bar-leading);
  letter-spacing: var(--bar-track);
}

.name {
  margin: 0;
  color: var(--name-ink);
  font-weight: var(--name-weight);
  white-space: nowrap;
}

.tabs {
  position: absolute;
  top: 50%;
  left: calc(50% + 0.5px);
  display: flex;
  gap: var(--tabs-gap);
  align-items: center;
  justify-content: center;
  padding: var(--tabs-pad);
  border: 1px solid var(--line);
  border-radius: var(--tabs-radius);
  background: var(--surface);
  box-shadow: 0 var(--tabs-lift) 0 var(--line);
  translate: -50% -50%;
}

/* One pill behind the tabs. tabs.js clips it to the current tab and springs it to the next. */
.pill {
  position: absolute;
  inset: var(--tabs-pad);
  border-radius: var(--tab-radius);
  background: var(--selected);
  clip-path: inset(0 100% 0 0 round var(--tab-radius));
  transition: background-color var(--motion-fast) var(--motion-ease-out);
}

/* Classic's pill takes the hover colour while it sits on a tab that is not the current one (tabs.js). */
.tabs.off-current .pill {
  background: var(--tab-hover);
}

.tabs .tab {
  position: relative;
  padding: var(--tab-pad-y) var(--tab-pad-x);
  border-radius: var(--tab-radius);
  color: color-mix(in srgb, var(--ink-nav) calc(var(--tab-dim) * 100%), transparent);
  white-space: nowrap;
  transition: color var(--jot-hover-fade, 150ms) ease;
}

@media (prefers-reduced-motion: reduce) {
  .tabs .tab { transition: none; }
}

.tabs:not(.live) .tab[aria-current],
.tabs .tab.lit,
.tabs .tab.hot {
  color: var(--ink-nav);
}

/* Jotion's hover fill, one per tab, under the pill and the text. tabs.js fades and scales it. */
.tab-fill {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: var(--tab-radius);
  background: var(--tab-hover);
  opacity: 0;
  pointer-events: none;
}

/* Until tabs.js runs, the current tab draws its own fill. */
.tabs:not(.live) .tab[aria-current] {
  background: var(--selected);
}

/* Tactile (Figma 928:34736). tabs.js wraps each label in a face and adds a shadow, and sets data-variant on the bar.
   The bar loses its tray and pill. Each face is a white key with a lip. tabs.js moves the face and fades it, the fill
   and the shadow; the button stays still, so the key never slides out from under the mouse. In the other variants the
   face is not drawn. */
.tab-face {
  display: contents;
}

.tab-shadow {
  display: none;
}

.tabs[data-variant="tactile"] {
  gap: var(--tac-gap);
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.tabs[data-variant="tactile"] .pill {
  display: none;
}

.tabs[data-variant="tactile"] .tab {
  padding: 0;
  border-radius: var(--tac-radius);
}

/* 2px of white around the fill, then the tab padding inside it. */
.tabs[data-variant="tactile"] .tab-face {
  display: block;
  position: relative;
  isolation: isolate;
  padding: calc(var(--tab-pad-y) + 2px) calc(var(--tab-pad-x) + 6px);
  border: 1px solid var(--line);
  border-radius: var(--tac-radius);
  background: var(--surface);
  box-shadow: 0 var(--lip, var(--tabs-lift)) 0 var(--line);
  color: color-mix(in srgb, var(--ink-nav) calc(var(--tab-dim) * 100%), transparent);
  opacity: var(--tac-rest);
  transition: color var(--motion-fast) var(--motion-ease-out);
}

.tabs[data-variant="tactile"] .tab.hot .tab-face {
  color: var(--ink-nav);
}

.tabs[data-variant="tactile"] .tab.up .tab-face {
  color: var(--tac-ink);
  opacity: 1;
}

.tabs[data-variant="tactile"] .tab-fill {
  inset: 2px;
  border-radius: max(0px, var(--tac-radius) - 2px);
  background: var(--tac-hover-fill);
  transition: background-color var(--motion-fast) var(--motion-ease-out);
}

.tabs[data-variant="tactile"] .tab.up .tab-fill {
  background: color-mix(in srgb, var(--selected) 80%, transparent);
  opacity: 1;
}

/* The raised key's shadow on the page, under the key's resting place. */
.tabs[data-variant="tactile"] .tab-shadow {
  display: block;
  position: absolute;
  top: calc(100% + 2.5px);
  left: 50%;
  z-index: -1;
  width: 43%;
  height: 6px;
  translate: -50% 0;
  background: url(icons/tab-shadow.svg) center / 100% 100% no-repeat;
  opacity: 0;
  pointer-events: none;
}

.tabs[data-variant="tactile"] .tab.up .tab-shadow {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .tabs[data-variant="tactile"] .tab-face,
  .tabs[data-variant="tactile"] .tab-fill { transition: none; }
}

/* Tray (Figma 931:35311): Tactile's keys, kept in the tray. The tabs sit plain in it until a click pops the current one out
   as a key, up over the tray's top edge, and leaves its shadow in the empty slot. The key's edge (::before) sits 3px
   outside the slot, so no tab changes size, and its white ring hides the tray's edge where the key crosses it. */
.tabs[data-variant="tray"] .pill {
  display: none;
}

/* The key stands raise - 4px above the tray, so the bar moves down to keep it 8px clear of the canvas, as in Figma. */
.bar:has(.tabs[data-variant="tray"]) {
  margin-top: max(var(--bar-top), var(--tray-raise-height) + 3.5px);
}

.tabs[data-variant="tray"] .tab {
  padding: 0;
}

.tabs[data-variant="tray"] .tab.up {
  z-index: 1;
}

.tabs[data-variant="tray"] .tab-face {
  display: block;
  position: relative;
  isolation: isolate;
  padding: var(--tab-pad-y) var(--tab-pad-x);
  color: color-mix(in srgb, var(--ink-nav) calc(var(--tab-dim) * 100%), transparent);
  transition: color var(--motion-fast) var(--motion-ease-out);
}

.tabs[data-variant="tray"] .tab-face::before {
  content: '';
  position: absolute;
  inset: -3px;
  z-index: -1;
  border: 1px solid var(--line);
  border-radius: var(--tray-radius);
  background: var(--surface);
  box-shadow: 0 4px 0 3px var(--surface), 0 var(--lip, var(--tabs-lift)) 0 var(--line);
  opacity: 0;
  transition: opacity var(--motion-fast) var(--motion-ease-out);
}

.tabs[data-variant="tray"] .tab.up .tab-face::before {
  opacity: 1;
}

.tabs[data-variant="tray"] .tab.hot .tab-face {
  color: var(--ink-nav);
}

.tabs[data-variant="tray"] .tab.up .tab-face {
  color: var(--tac-ink);
}

.tabs[data-variant="tray"] .tab-fill {
  border-radius: max(0px, var(--tray-radius) - 4px);
  background: var(--tac-hover-fill);
  transition: background-color var(--motion-fast) var(--motion-ease-out);
}

.tabs[data-variant="tray"] .tab.up .tab-fill {
  background: color-mix(in srgb, var(--selected) 80%, transparent);
  opacity: 1;
}

.tabs[data-variant="tray"] .tab-shadow {
  display: block;
  position: absolute;
  top: calc(100% - 11px);
  left: 50%;
  z-index: -1;
  width: 43%;
  height: 6px;
  translate: -50% 0;
  background: url(icons/tab-shadow.svg) center / 100% 100% no-repeat;
  opacity: 0;
  pointer-events: none;
}

.tabs[data-variant="tray"] .tab.up .tab-shadow {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .tabs[data-variant="tray"] .tab-face,
  .tabs[data-variant="tray"] .tab-face::before,
  .tabs[data-variant="tray"] .tab-fill { transition: none; }
}

.links {
  display: flex;
  gap: var(--link-gap);
  align-items: center;
  padding-left: 6px;
}

.links button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--link-size);
  height: var(--link-size);
  padding: 0;
  border-radius: var(--link-radius);
  color: var(--icon);
  transition: color var(--motion-fast) var(--motion-ease-out), transform var(--motion-fast) var(--motion-ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .links button:hover {
    color: var(--icon-hover);
  }
}

/* Touch: every control gets a 44px target. Icons stay 20px. Tabs reach above and below their pill. */
@media (pointer: coarse) {
  .links {
    --link-size: var(--hit-min);
    --link-gap: 0px;
  }

  .tabs .tab::before {
    content: '';
    position: absolute;
    inset: calc(50% - var(--hit-min) / 2) calc(var(--tabs-gap) / -2);
  }
}

.links svg {
  display: block;
  width: var(--link-icon);
  height: var(--link-icon);
  transition: transform var(--motion-medium) var(--ease-pop);
}

/* Pixel icons (links.js): 24px, so each 2-unit art pixel is two screen pixels; all three the same size. */
html.pixel-icons .links button svg {
  width: 24px;
  height: 24px;
}

/* LinkedIn's square reads small beside the others, so its icon is 4px larger. The button keeps its size, so the row holds. */
.links button[aria-label="LinkedIn"] svg {
  width: calc(var(--link-icon) + 4px);
  height: calc(var(--link-icon) + 4px);
}

/* Hover lifts and tilts the icon. The overshoot curve gives it a small bounce as it settles.
   Icons alternate left, right, left. links.js sets --tilt-jitter on each hover so the size varies. */
.links button:nth-child(even) svg {
  --tilt-side: -1;
}

@media (hover: hover) and (pointer: fine) {
  .links button:hover svg {
    transform: translateY(var(--icon-lift)) rotate(calc(var(--icon-tilt) * var(--tilt-side, 1) * var(--tilt-jitter, 1)));
  }
}

/* Goodbye (index.html, footer.js), Figma node 991:15005. The box is the room the page scrolls by; what it shows lies
   behind everything until the card moves up off it, and comes to rest centred in the window above the bar (--bar-zone,
   footer.js). On the way it rises at --footer-parallax of the scroll speed, as emmiwu.com's footer does (0.3 there):
   it starts that share of --reveal lower, tucked under the card, and climbs into place as the card leaves. The page
   scrolls only to show the goodbye, so the root scroll timeline runs exactly over the reveal. A scroll-driven animation
   keeps it on the scroll itself, wheel or touch, off the main thread
   (https://developer.chrome.com/docs/css-ui/scroll-driven-animations); without one, or with reduced motion, it holds still. */
.goodbye {
  flex: none;
  height: var(--reveal, 0px);
}

.goodbye-view {
  position: fixed;
  z-index: -1;
  inset: 0 0 var(--bar-zone, 0px);
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 16px;
}

@keyframes goodbye-rise {
  from { translate: 0 calc(var(--footer-parallax) * var(--reveal, 0px)); }
  to { translate: 0 0; }
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .goodbye-view {
      animation: goodbye-rise linear both;
      animation-timeline: scroll(root);
    }
  }
}

/* The photo, cropped as Figma crops it, with Rachel's grain over it once more (as body::after, at --footer-grain). */
.goodbye-photo {
  position: relative;
  width: 280px;
  height: 196px;
  overflow: hidden;
  border-radius: 24px;
}

.goodbye-photo img {
  position: absolute;
  top: -20.61%;
  left: -31.79%;
  width: 131.61%;
  height: 120.45%;
  max-width: none;
}

.goodbye-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  opacity: var(--footer-grain);
  mix-blend-mode: multiply;
  background: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0 / var(--footer-grain-size) repeat;
  pointer-events: none;
}

/* The photo as pixel art (goodbye-art.js): a canvas in its place, with its corners stepped and the grain drawn in, so
   the box neither rounds nor grains it again. The canvas can run half a pixel past the box, to end on a whole art pixel. */
.goodbye-art-on .goodbye-photo {
  overflow: visible;
}

.goodbye-art-on .goodbye-photo img,
.goodbye-art-on .goodbye-photo::after {
  visibility: hidden;
}

.goodbye-art {
  position: absolute;
  top: 0;
  left: 0;
}

.goodbye p {
  width: 280px;
  margin: 0;
  color: var(--footer-ink);
  font-size: 14px;
  line-height: 1.3;
  text-align: center;
}

/* The design covers desktop only. On narrow screens the tabs take their own row. */
@media (max-width: 560px) {
  .bar {
    display: grid;
    grid-template-columns: 1fr auto;
    row-gap: 8px;
    height: auto;
    margin-inline: 16px;
  }

  .tabs {
    position: static;
    grid-column: 1 / -1;
    order: -1;
    justify-self: center;
    position: relative;
    top: auto;
    left: auto;
    translate: none;
  }
}

/* Every load: the scene waits hidden for the wind scene, which intro.js staggers in; the head script clears scene-wait after
   5s if anything fails. First visit this session: .intro holds the down arrow for intro.js too, cleared after 3s. */
.scene-wait .scene,
.intro .down {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  button {
    transition: none;
  }

  .links button {
    transition: none;
  }

  .links button:active {
    transform: none;
  }

  .links svg {
    transition: none;
  }

  .links button:hover svg {
    transform: none;
  }
}

/* The dot cursor (cursor.js). While it is on, the arrow hides everywhere but fields, which keep the text cursor.
   The dot sits on the pointer; inside it, one layer shrinks and hops about the pointer itself. */
html.dot-cursor-on,
html.dot-cursor-on * {
  cursor: none !important;
}

/* The stemless arrow across the whole site (--cursor: stemless): macOS's arrow without its stem (cursor/arrow.svg, drawn
   to arrow.png and arrow@2x.png) as the real cursor, so it never trails the pointer. Its tip, 2.8 by 2.2, is the hotspot.
   It stays over links and buttons too. */
html.arrow-cursor-on,
html.arrow-cursor-on * {
  cursor: url("cursor/arrow.png") 3 2, default !important;
  cursor: image-set(url("cursor/arrow.png") 1x, url("cursor/arrow@2x.png") 2x) 3 2, default !important;
}

:is(html.dot-cursor-on, html.arrow-cursor-on) :is(input:not([type="range"], [type="checkbox"], [type="radio"], [type="button"], [type="submit"], [type="color"]), textarea, [contenteditable]:not([contenteditable="false"])) {
  cursor: text !important;
}

.dot-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483647;
  pointer-events: none;
  transition: opacity var(--motion-fast) var(--motion-ease-out);
}

html:not(.dot-cursor-on) .dot-cursor,
.dot-cursor.gone,
.dot-cursor.away {
  opacity: 0;
}

.dot-hop {
  position: relative;
  display: block;
  width: 0;
  height: 0;
}

/* The spiral the dot can turn into on hover (cursor.js, --cursor-hover: spiral). Hidden until then. */
.dot-spiral {
  position: absolute;
  top: calc(var(--cursor-size) / -2);
  left: calc(var(--cursor-size) / -2);
  width: var(--cursor-size);
  height: var(--cursor-size);
  overflow: visible;
  opacity: 0;
}

.dot-spiral path {
  fill: none;
  stroke: #2d2222;
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.dot-spiral .edge {
  display: none;
}

/* White (--cursor-color: white): the dot is filled white inside a 1px #2d2222 outline (the stroke is drawn first, so
   only its outer half shows), and the spiral is a white line on a wider #2d2222 one. */
.dot-shape {
  overflow: visible;
}

.dot-shape path {
  fill: #2d2222;
}

.dot-cursor.white .dot-shape path {
  fill: #ffffff;
  stroke: #2d2222;
  stroke-width: 1.33; /* 2px at 12px wide (8 units), half of it outside: a 1px outline */
  stroke-linejoin: miter;
  paint-order: stroke fill;
}

.dot-cursor.white .dot-spiral .edge {
  display: inline;
  stroke-width: 2.6;
}

.dot-cursor.white .dot-spiral .line {
  stroke: #ffffff;
}

.dot-hop .dot-shape {
  position: absolute;
  top: calc(var(--cursor-size) / -2);
  left: calc(var(--cursor-size) / -2);
  display: block;
  width: var(--cursor-size);
  height: var(--cursor-size);
  max-width: none;
}

/* The bush cursor (cursor.js, Figma frame 1003:501): over the autumn bush, an arrow with a "Rummage" label beside it.
   The box sits on the pointer; the arrow's tip (2.8, 2.2 in its own pixels) is the pointer, and the label's corner sits
   3px right and 13.6px down from the tip, as in Figma, just under the stemless arrow. data-bush-arrow on the root says
   which arrow: stemless, drawn here while the system arrow hides; stem, the system arrow, shown even over the dot, with
   the label dropped 3px more to clear the stem (Figma's macOS 26 arrow, node 1005:926, ends 15.9px below its tip); or
   site, the site's own stemless arrow, left as it is. */
html.bush-cursor-on[data-bush-arrow="stemless"],
html.bush-cursor-on[data-bush-arrow="stemless"] * {
  cursor: none !important;
}

html.bush-cursor-on[data-bush-arrow="stem"],
html.bush-cursor-on[data-bush-arrow="stem"] * {
  cursor: default !important;
}

.bush-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483647;
  pointer-events: none;
}

.bush-arrow {
  position: absolute;
  top: -2.2px;
  left: -2.8px;
  display: block;
  width: 13.9767px;
  height: 17.7261px;
  max-width: none;
  opacity: 0;
  transform-origin: 2.8px 2.2px;
}

.bush-label {
  position: absolute;
  top: 13.6px;
  left: 3px;
  padding: 4px 7px;
  border-radius: 6px;
  background: #f5f2f2;
  color: #221c19;
  font: 300 12px/normal 'TWK Lausanne', system-ui, sans-serif;
  letter-spacing: -0.18px;
  white-space: nowrap;
  opacity: 0;
  transform-origin: 0 50%;
}

.bush-cursor[data-arrow="stem"] .bush-label {
  top: 16.6px;
}

/* --cursor-label-style: word, the word alone, with no chip and no padding. It sits beside the arrowhead, 12px right of
   the tip and 5px down, so its baseline meets the foot of the stemless arrow; the same spot clears the stem. */
.bush-cursor[data-label="word"] .bush-label {
  top: 5px;
  left: 12px;
  padding: 0;
  border-radius: 0;
  background: none;
  line-height: 1;
}

