/*
 * Cursor dot — rose pointer for real fine-mouse input.
 *
 * It replaces the native arrow only after JS receives and positions a real
 * mouse pointer. Outside that state, the native cursor remains active:
 *
 *   - keyboard users have a focus ring they can see
 *   - assistive tech that reads cursor:none is unaffected
 *   - touch input has no overlay under a non-existent pointer (we also
 *     skip the JS entirely on coarse pointers, see cursor.js)
 *
 * When the visitor hovers anything marked [data-cursor], the dot grows
 * and shows its cue: [data-cursor-cue], or the cue cursor.js assigns by type.
 */

:root {
  /*
   * The dot at rest is the anchor rose (var(--rose)).
   * On hover, the pill blossoms into the deep indigo watercolor wash.
   */
  --cursor-size: 9px;
  --cursor-size-hover: 64px;
  --cursor-color: var(--anchor-red);
  --cursor-color-hover: var(--indigo);
  --cursor-label-color: var(--white);
}

.cursor-dot {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--cursor-size);
  height: var(--cursor-size);
  border-radius: var(--radius-pill);
  background: var(--cursor-color);
  opacity: 0;
  pointer-events: none;
  z-index: 9999;

  /*
   * The size the pill opens to, set per hover target in cursor.js. The header
   * and the two side edges are thin targets — a 64px pill beside them would
   * shout over the whole page — so they ask for a smaller step.
   */
  --pill-h: var(--cursor-size-hover);
  --pill-pad: 22px;

  /* JS places the box at the pointer; this centers it in both dot and pill states. */
  /*
   * The rim is always present, just transparent at rest, so opening the pill
   * is a colour change rather than a border arriving — a 2px ring popping
   * into existence under the pointer reads as a glitch, not as the dot
   * opening. box-sizing is border-box so the 64px height is the pill, not
   * the pill plus its rim.
   */
  box-sizing: border-box;
  border: 2px solid transparent;

  translate: -50% -50%;
  transition:
    width 0.28s var(--ease-standard),
    height 0.28s var(--ease-standard),
    min-width 0.28s var(--ease-standard),
    padding 0.28s var(--ease-standard),
    background-color 0.28s var(--ease-standard),
    border-color 0.28s var(--ease-standard),
    translate 0.28s var(--ease-standard);

  /*
   * The label sits inside the dot, hidden until hover. The dot has
   * overflow:hidden so the text only appears when the dot is large enough
   * to hold it.
   */
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;

  /*
   * No text selection on the label. The dot is a passive UI layer; clicking
   * through it must not select adjacent text on the page underneath.
   */
  user-select: none;
  -webkit-user-select: none;
}

/*
 * The wash.
 *
 * A pill filled flat rose is a button. A pill of rose thinning to nothing
 * at two different centres is pigment on wet paper: where the two passes meet
 * the colour is deepest, and towards the rim it has run out of paint and the
 * paper shows through.
 *
 * It lives on a pseudo-element so it can fade in — a gradient itself cannot
 * be interpolated, so swapping `background-image` on hover would snap. The
 * flat colour underneath fades out while this fades in.
 */
.cursor-dot::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background-image:
    /*
     * Radii are deliberately smaller than the pill. A gradient whose
     * transparent stop falls outside the box is just a flat fill — which is
     * what the first attempt was, measured at ~100% colour edge to edge.
     * The wide pass sets the falloff, the tight one deepens the middle only
     * and is already spent by the time it reaches the rim.
     */
    radial-gradient(66% 78% at 46% 46%, var(--cursor-color-hover) 0%, transparent 100%),
    radial-gradient(34% 40% at 52% 54%, var(--cursor-color-hover) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.28s var(--ease-standard);
}

/*
 * One line of Chinese: the verb for what pressing here does. Display serif,
 * set from the site's type scale so it matches the labels on the page.
 */
.cursor-dot__label {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Above the wash pseudo-element, which is absolutely positioned and would
     otherwise paint over the text. */
  position: relative;
  z-index: 1;
  color: var(--cursor-label-color);
  white-space: nowrap;
  opacity: 0;
  transform: translateX(6px);
  transition: opacity 0.24s var(--ease-standard),
              transform 0.24s var(--ease-standard);
}

.cursor-dot__cue {
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: 400;
  line-height: 1;
  letter-spacing: var(--tracking-label);
}

/*
 * Hover state. The class lives on documentElement so the dot reads from
 * one source of truth and CSS does not need to coordinate with JS more
 * than toggling a single attribute.
 *
 * The dot opens into a pill: 64px tall, its width carried by the cue. It
 * stays centred on the hotspot, so the pointer is still the exact thing
 * being clicked. The cue says what pressing does, not the name underneath,
 * so a two- or three-character verb is all the pill ever has to hold.
 */
/*
 * Two smaller steps. `--pill-h` is all the hover rule reads, so a target only
 * has to name its step and height, minimum width and both type sizes follow.
 */
.cursor-dot[data-size="mid"] {
  --pill-h: 50px;
  --pill-pad: 18px;
}

.cursor-dot[data-size="small"] {
  --pill-h: 36px;
  --pill-pad: 14px;
}
.cursor-dot[data-size="small"] .cursor-dot__cue { font-size: var(--text-sm); }

html[data-cursor="hover"] .cursor-dot {
  width: auto;
  min-width: var(--pill-h);
  height: var(--pill-h);
  padding-inline: var(--pill-pad);

  /*
   * The flat fill empties out. Premultiplied interpolation means the rose
   * fades on its own hue rather than through grey, and what is left behind
   * is the rose wash above thinning to nothing.
   */
  background-color: transparent;
  border-color: var(--cursor-color-hover);
  translate: -50% -50%;
}

html[data-cursor="hover"] .cursor-dot::before {
  opacity: 1;
}

html[data-cursor="hover"] .cursor-dot__label {
  opacity: 1;
  transform: translateX(0);
}

/*
 * Typing: shrink the rose dot to 6px, parked under the caret.
 * The caret already blinks; the dot stays still.
 */
.cursor-dot[data-state="text"] {
  width: 6px;
  height: 6px;
  background: var(--anchor-red);
}

/*
 * Reduced-motion: no transitions, dot is always exactly where the cursor
 * is. JS already skipped rAF easing under reduced motion by setting a body
 * class; CSS short-circuits the hover transitions for completeness.
 */
body.is-cursor-reduced .cursor-dot,
body.is-cursor-reduced .cursor-dot__label {
  transition: none;
}

/*
 * Once the pointer has entered and the dot has a real position, the OS arrow
 * is redundant, and a 64px pill with an
 * arrow poking out of it reads as two pointers arguing.
 *
 * Guarded by `.has-cursor`, which cursor.js sets only after a real pointermove
 * has positioned the dot. A visitor with JS off, keyboard input, touch input,
 * or a pointer outside the page keeps the native cursor. Focus rings remain
 * independent.
 */
html.has-cursor,
html.has-cursor * {
  cursor: none;
}
html.has-cursor .cursor-dot { opacity: 1; }
body.is-home-rose .cursor-dot {
  border-width: 1px;
  border-color: var(--indigo-deep);
  transition: border-color 0s;
}

/*
 * Touch / coarse pointer: the JS does not run. The CSS class below is
 * defensive — if the JS ever ships its DOM before early-returning, hide
 * the orphan node rather than let it sit on screen at (0,0).
 */
@media (pointer: coarse) {
  .cursor-dot {
    display: none;
  }
}
