/* Live cursors and cursor chat (live-cursors.js): desktop only, above all page content. */
.live-layer { position: fixed; z-index: 20; inset: 0; overflow: hidden; pointer-events: none; }
.live-cursor { position: absolute; left: 0; top: 0; will-change: transform; transition: opacity 200ms ease; }
/* Other visitors' cursors fade while their pointer is off the page or on content this view lacks. */
.live-cursor:not(.is-placed) { visibility: hidden; }
.live-cursor.is-away { opacity: 0; }
.live-cursor svg { display: block; transform-origin: 2px 2px; filter: drop-shadow(0 1px 2px #0006); }
.live-cursor path { fill: var(--cursor); stroke: #fff; stroke-width: 1.5; stroke-linejoin: round; }
.live-label { position: absolute; left: 13px; top: 15px; display: flex; flex-direction: column; gap: 3px; padding: 4px 7px 5px; border-radius: 4px 10px 10px; background: var(--cursor); box-shadow: 0 1px 3px #0005; color: #fff; font: 400 11.5px/1 'Inter', sans-serif; white-space: nowrap; }
.live-message { display: none; }
/* While a visitor types, the name tag grows into a speech bubble. */
.live-cursor.is-chatting .live-label { padding: 6px 11px 8px; border-radius: 4px 14px 14px; }
.live-cursor.is-chatting .live-name { font-size: 10.5px; opacity: .8; }
.live-cursor.is-chatting .live-message { display: block; width: max-content; max-width: 240px; font-size: 13px; line-height: 1.35; white-space: normal; overflow-wrap: anywhere; }
/* Near the window edges a label moves to the other side of its pointer; the square corner stays nearest the tip. */
.is-flip-x :is(.live-label, input) { left: auto; right: 13px; }
.live-cursor.is-flip-y .live-label { top: auto; bottom: 20px; }
.live-cursor.is-flip-y .live-label { border-radius: 10px 10px 10px 4px; }
.live-cursor.is-flip-x .live-label { border-radius: 10px 4px 10px 10px; }
.live-cursor.is-flip-x.is-flip-y .live-label { border-radius: 10px 10px 4px 10px; }
:is(.live-cursor.is-chatting, .live-chat).is-flip-y :is(.live-label, input) { border-radius: 14px 14px 14px 4px; }
:is(.live-cursor.is-chatting, .live-chat).is-flip-x :is(.live-label, input) { border-radius: 14px 4px 14px 14px; }
:is(.live-cursor.is-chatting, .live-chat).is-flip-x.is-flip-y :is(.live-label, input) { border-radius: 14px 14px 4px 14px; }

/* This visitor's own name tag: the same label as a peer's, beside the native pointer instead of a drawn one. */
.live-self { --cursor: var(--self, #0d99ff); position: absolute; left: 0; top: 0; will-change: transform; opacity: 0; transition: opacity 150ms ease; }
.live-self.is-visible { opacity: 1; }
:is(.live-self, .live-chat) :is(.live-label, input) { left: 14px; top: 20px; }
:is(.live-self, .live-chat).is-flip-x :is(.live-label, input) { left: auto; right: 6px; }
:is(.live-self, .live-chat).is-flip-y :is(.live-label, input) { top: auto; bottom: 8px; }
.live-self.is-flip-y .live-label { border-radius: 10px 10px 10px 4px; }
.live-self.is-flip-x .live-label { border-radius: 10px 4px 10px 10px; }
.live-self.is-flip-x.is-flip-y .live-label { border-radius: 10px 10px 4px 10px; }

/* This visitor's own bubble, opened with "/"; it takes the name tag's place. */
.live-chat { --cursor: #0d99ff; position: fixed; z-index: 21; left: 0; top: 0; pointer-events: none; }
.live-chat[hidden] { display: none; }
.live-chat input { position: absolute; width: 220px; min-width: 14ch; max-width: 260px; margin: 0; padding: 7px 11px 8px; border: 0; border-radius: 4px 14px 14px; background: var(--cursor); box-shadow: 0 1px 3px #0005; color: #fff; font: 400 13px/1.35 'Inter', sans-serif; caret-color: #fff; outline: none; }
@supports (field-sizing: content) {
  .live-chat input { width: auto; field-sizing: content; }
}
.live-chat input::placeholder { color: #ffffffb8; }
/* The bubble opening is the focus cue; a quiet inner ring keeps it visible for keyboard users. */
.live-chat input:focus-visible { box-shadow: 0 1px 3px #0005, inset 0 0 0 1.5px #ffffff73; }
.live-chat input:read-only { caret-color: transparent; }

/* A bubble that goes away poofs into a cartoon cloud (cloudPoof in live-cursors.js): it
   squashes away under the cloud, then the name tag puffs back in (puffIn), growing from
   the corner nearest the pointer. */
:is(.live-cursor, .live-self, .live-chat) :is(.live-label, input) { transform-origin: left top; }
:is(.live-cursor, .live-self, .live-chat).is-flip-x :is(.live-label, input) { transform-origin: right top; }
:is(.live-cursor, .live-self, .live-chat).is-flip-y :is(.live-label, input) { transform-origin: left bottom; }
:is(.live-cursor, .live-self, .live-chat).is-flip-x.is-flip-y :is(.live-label, input) { transform-origin: right bottom; }
:is(.live-cursor, .live-chat).is-puffing :is(.live-label, input) { animation: live-squash 180ms ease-in forwards; }
@keyframes live-squash {
  from { transform-origin: center; }
  to { transform-origin: center; transform: scale(.6, .5); opacity: 0; }
}
/* Each cloud is one circle with three lobes: a lighter tint of the bubble, shaded underneath, as in a cartoon puff. */
.live-poof { --poof-light: color-mix(in srgb, var(--poof), #fff 30%); --poof-shade: color-mix(in srgb, var(--poof), #000 8%); position: absolute; left: 0; top: 0; }
.live-poof span { --l: calc(var(--d) * -.13); position: absolute; left: 0; top: 0; width: var(--d); height: var(--d); margin: calc(var(--d) / -2); border-radius: 50%; background: var(--poof-light); box-shadow:
  inset 0 calc(var(--d) * -.1) 0 var(--poof-shade),
  calc(var(--d) * .42) calc(var(--d) * .06) 0 var(--l) var(--poof-light),
  calc(var(--d) * -.4) calc(var(--d) * .1) 0 calc(var(--l) * 1.3) var(--poof-light),
  calc(var(--d) * .08) calc(var(--d) * -.32) 0 var(--l) var(--poof-light),
  calc(var(--d) * .42) calc(var(--d) * .14) 0 var(--l) var(--poof-shade),
  calc(var(--d) * -.4) calc(var(--d) * .18) 0 calc(var(--l) * 1.3) var(--poof-shade); }
/* Four-point sparkles. */
.live-poof i { position: absolute; left: 0; top: 0; width: var(--d); height: var(--d); margin: calc(var(--d) / -2); background: #ffc933; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); }
@media (prefers-reduced-motion: reduce) {
  :is(.live-cursor, .live-chat).is-puffing :is(.live-label, input) { animation-name: live-fade; }
  @keyframes live-fade { to { opacity: 0; } }
}

/* The hint sits just above the footer links, out of flow so they don't jump when it appears. */
.portfolio-page > .site-footer { position: relative; }
.live-hint { position: absolute; left: 0; top: -4px; }
.live-hint[hidden] { display: none; }
.live-hint kbd { display: inline-block; min-width: 18px; padding: 0 4px; border: 1px solid currentColor; border-radius: 4px; font: inherit; line-height: 1.4; text-align: center; opacity: .8; }
@media not ((min-width: 761px) and (hover: hover) and (pointer: fine)) {
  .live-layer, .live-chat, .live-hint { display: none !important; }
}
