/* Texu, the living mascot (texu.js). The body is filled with the colour behind it, so legs that pass
   behind the body are hidden: containers on a panel set --texu-fill: var(--panel).
   All motion of the body, legs, thread and held thing is drawn by texu.js frame by frame (SVG
   attributes); CSS here only styles it and switches the eyes (blink, happy, dizzy). Never put a CSS
   transform on .tx-body, .tx-eyes, .tx-leg, .tx-prop or .tx-rig: it would override the rig. */

.texu { --texu-fill: var(--bg); display: inline-block; width: 8rem; aspect-ratio: 200 / 140; position: relative; cursor: pointer; -webkit-tap-highlight-color: transparent; vertical-align: bottom; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.tx-svg { width: 100%; height: 100%; display: block; overflow: visible; }
.tx-leg, .tx-shell, .tx-thread { fill: none; stroke: var(--spider); stroke-width: 7; stroke-linecap: round; stroke-linejoin: round; transition: stroke .3s ease; }
.tx-shell { fill: var(--texu-fill); }
.tx-thread { stroke-width: 2.6; opacity: 0; }
.on-thread .tx-thread { opacity: .9; }
.tx-eyes circle { fill: var(--text); }
.tx-happy path { fill: none; stroke: var(--text); stroke-width: 4.4; stroke-linecap: round; opacity: 0; transition: opacity .12s ease; }

/* ---- eyes: blink, happy arcs, closed while asleep, spirals when dizzy ---- */
.tx-eye { transform-box: fill-box; transform-origin: center; transition: transform .07s ease, opacity .12s ease; }
.blink .tx-eye, .mood-sleep .tx-eye { transform: scaleY(.1); }
.happy .tx-eye, .giggle .tx-eye, .pet .tx-eye, .dizzy .tx-eye { opacity: 0; }
.happy .tx-happy path, .giggle .tx-happy path, .pet .tx-happy path { opacity: 1; }
.tx-dizzy path { fill: none; stroke: var(--text); stroke-width: 2.4; stroke-linecap: round; opacity: 0; transform-box: fill-box; transform-origin: center; }
.dizzy .tx-dizzy path { opacity: 1; animation: tx-turn .7s linear infinite; }
.grabbed { cursor: grabbing; }

/* ---- the heart that floats up when pressed ---- */
.tx-heart { position: absolute; left: 50%; top: 4%; width: 22%; pointer-events: none; z-index: 1; }
.tx-heart svg { display: block; width: 100%; overflow: visible; }
.tx-heart path { fill: #f3bf4b; stroke: var(--text); stroke-width: 3.6; stroke-linejoin: round; }

.texu.drop { animation: tx-drop 1.1s cubic-bezier(.25, 1.4, .5, 1) both; }
@keyframes tx-turn { to { transform: rotate(360deg); } }
@keyframes tx-drop { from { transform: translateY(-120%); opacity: 0; } 30% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .texu *, .texu { animation: none !important; transition: none !important; }
}

/* ---- the helper in the corner (helper.js) ---- */
.helper { position: fixed; right: clamp(.8rem, 2vw, 1.6rem); bottom: clamp(.6rem, 2vh, 1.2rem); z-index: 35; display: flex; align-items: flex-end; gap: .4rem; pointer-events: none; }
.helper .texu { width: 5.4rem; pointer-events: auto; animation: tx-peek .9s cubic-bezier(.3, 1.4, .5, 1) 1.2s both; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .08)); }
.helper.asleep .texu { opacity: .55; width: 4rem; }
.helper.gone { display: none; }
.helper-bubble { pointer-events: auto; max-width: min(21rem, 70vw); background: var(--panel); border: 1px solid var(--line); border-radius: 16px 16px 4px 16px; padding: .8rem 2.2rem .7rem 1rem; box-shadow: var(--shadow); position: relative; margin-bottom: 3.2rem; opacity: 0; transform: translateY(10px) scale(.96); transform-origin: 100% 100%; transition: opacity .25s ease, transform .35s cubic-bezier(.2, .9, .3, 1.2); visibility: hidden; }
.helper.talking .helper-bubble { opacity: 1; transform: none; visibility: visible; }
.helper-bubble p { margin: 0; font-weight: 600; font-size: .95rem; line-height: 1.4; }
.helper-x { position: absolute; right: .4rem; top: .3rem; background: none; border: 0; color: var(--soft); font-size: 1.2rem; line-height: 1; padding: .2rem .35rem; }
.helper-off { background: none; border: 0; padding: .35rem 0 0; color: var(--soft); font-weight: 700; font-size: .82rem; text-decoration: underline; }
.helper-off:hover, .helper-x:hover { color: var(--text); }
@keyframes tx-peek { from { transform: translateY(120%); } }
/* On a phone the corner helper would sit on the text all the time, so it stays away. */
@media (max-width: 700px) { .helper { display: none; } }

/* ---- something held in the front left leg; texu.js moves it with the shin ---- */
.tx-prop path, .tx-prop circle, .tx-prop ellipse { fill: none; stroke: var(--text); stroke-width: 4.2; stroke-linecap: round; stroke-linejoin: round; }
.tx-prop .tp-fill.gold { fill: #f3bf4b; }
.tx-prop .tp-fill.ink { fill: var(--text); }
.tx-prop .tp-cut { stroke: var(--texu-fill); stroke-width: 3; }
.tx-pop { transform-box: view-box; transform-origin: 29px 53px; }
/* The turn on the spot is drawn by texu.js in 3D (legs fan round the body, eyes slide round the ball). */

/* ---- Texu on a thread at the right edge of the site (companion.js) ---- */
.buddy { position: fixed; top: 0; right: clamp(.3rem, 1.3vw, 1.7rem); width: clamp(4.2rem, 4.4vw, 5.6rem); height: 0; z-index: 34; pointer-events: none; }
.buddy.gone { display: none; }
.buddy-rig { position: absolute; left: 50%; top: 0; width: 0; height: 0; transform-origin: 0 0; will-change: transform; }
.buddy-line { position: absolute; left: -1px; top: 0; width: 2px; background: var(--spider); opacity: .8; border-radius: 2px; }
.buddy-spider { position: absolute; left: 0; top: 0; width: clamp(4.2rem, 4.4vw, 5.6rem); margin-top: -.22em; font-size: clamp(4.2rem, 4.4vw, 5.6rem); line-height: 0; pointer-events: auto; cursor: grab; touch-action: none; transform-origin: 50% 0; }
.buddy-spider .texu { width: 100%; --texu-fill: var(--bg); filter: drop-shadow(0 6px 8px rgba(0, 0, 0, .1)); }
.buddy.held .buddy-spider { cursor: grabbing; }
.buddy.up .buddy-spider { pointer-events: none; }
/* Dozing: little z's float up. */
.buddy.dozing .buddy-spider::after { content: 'z'; position: absolute; right: -.1em; top: .05em; font: 800 .26em/1 inherit; color: var(--soft); animation: bz 2.4s ease-in-out infinite; }
@keyframes bz { 0% { opacity: 0; transform: translate(0, 0) scale(.6); } 30% { opacity: 1; } 100% { opacity: 0; transform: translate(.4em, -.9em) scale(1.1); } }
/* What it says: a bubble to its left, level with its body. */
.buddy-say { position: absolute; right: calc(100% + .3rem); top: 0; width: max-content; max-width: min(20rem, 60vw); pointer-events: auto; background: var(--panel); border: 1px solid var(--line); border-radius: 16px 4px 16px 16px; padding: .75rem 2.1rem .65rem .95rem; box-shadow: var(--shadow); opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility .25s; }
.buddy-say p { margin: 0; font-weight: 600; font-size: .95rem; line-height: 1.4; }
.buddy.talking .buddy-say { opacity: 1; visibility: visible; }
.buddy.up .buddy-say { opacity: 0; visibility: hidden; }
.buddy-x { position: absolute; right: .35rem; top: .25rem; background: none; border: 0; color: var(--soft); font-size: 1.2rem; line-height: 1; padding: .2rem .35rem; }
.buddy-off { background: none; border: 0; padding: .35rem 0 0; color: var(--soft); font-weight: 700; font-size: .82rem; text-decoration: underline; }
.buddy-off:hover, .buddy-x:hover { color: var(--text); }
@media (max-width: 760px) { .buddy { display: none; } }
@media (prefers-reduced-motion: reduce) { .buddy.dozing .buddy-spider::after { animation: none; opacity: .7; } }
