/*
  eddi.css: Eddi, the sea trout, house mascot of the Eider apps.

  Load after the house styles (eider-design.css, or tokens.css, base.css and
  components.css). In an app it lives in the mascot folder of the shared app
  (EiderDo: core/static/core/mascot/eddi.css) and is linked in <head> only
  when the page shows Eddi. House tokens used here: --surface, --ink,
  --ink-soft, --line, --shadow, --radius, --font and --focus-ring.

  Rules kept here:
  - Hex values appear only inside custom property declarations.
  - Only transform and opacity are animated, so every frame stays on the
    compositor and never triggers layout.
  - All motion stops under prefers-reduced-motion and html[data-motion="reduce"].
    Each state then shows a calm static pose (section 9).
  - State lives on .eddi-dock as data attributes:
      data-state  idle, blink, look, talk, wave, happy, leap, celebrate,
                  think, surprised, concerned, sleep, drag, swim, dive, surface
      data-skin   captain, christmas, new-year, easter, spring, kieler-woche,
                  summer, rain, halloween, advent, winter (empty: no skin)
      data-edge   left or right, data-v top or bottom (the resting corner)
  - One shot states (blink, happy, leap, celebrate, surprised, dive, surface)
    fire animationend on .eddi-float, so the script knows when to go back to
    idle. dive keeps its last frame (Eddi is gone) until the script hides
    the dock. All other states loop. Under reduced motion nothing runs and
    no event fires, so the script also keeps a timer as a fallback.
  - Positions are set by the script through the CSSOM (--eddi-top for the
    corner, --eddi-shift-x and --eddi-shift-y for dragging and gliding),
    which the CSP allows.

  Layers, so motion and expression never fight over one transform:
  1. expression: which mouth, which lids, brow and pupil offsets. Set by
     custom properties per state, always active, eased by transitions.
  2. motion: keyframes on the float, fish, fin, tail and effect groups.
  3. pose: under reduced motion the motion groups read --eddi-pose-* instead.
*/

/* 1. Tokens */

:root,
[data-eddi-theme="light"] {
  --eddi-size: 88px;
  --eddi-gap: 16px;
  /* House z-index scale: tabbar 10, header 20, popover and menu 100,
     Eddi 150, dialog 200, toast 300. Top corners start below the header,
     and the script moves him off an open menu. */
  --eddi-z: 150;
  /* Overshoot for expressions and landings: a little life, no bounce show. */
  --eddi-pop: cubic-bezier(.34, 1.56, .64, 1);
  --eddi-soft: cubic-bezier(.45, 0, .25, 1);

  /* Amtsblau is the body. Shade and light are the same hue, so the trout
     reads as one flat colored object with volume, not as a gradient. */
  --eddi-body: #0068b1;
  --eddi-body-shade: #00528f;
  --eddi-body-light: #3794da;
  --eddi-spot: #56a7e2;
  --eddi-fin: #0b5b99;
  --eddi-fin-light: #2b86cc;
  --eddi-tail-light: #1a72b6;
  /* The pectoral fins are lighter than the body: they are Eddi's hands and
     have to read over the blue body and against a light page. */
  --eddi-pec: #3590d6;
  --eddi-pec-light: #6fb4ea;
  /* Two warm accents only. Coral: cheeks, both pectoral tips and the
     adipose tip. Deep coral: tongue, party hat and its confetti. A third
     orange on the adipose fin fought with the pinker cheeks for the eye. */
  --eddi-coral: #ff8a78;
  --eddi-coral-deep: #ee6a5e;
  --eddi-belly: #eef6fc;
  --eddi-belly-shade: #bed8ee;
  --eddi-eye-white: #ffffff;
  --eddi-pupil: #0d2238;
  --eddi-shine: #ffffff;
  --eddi-brow: #0b3558;
  --eddi-mouth: #0d2238;
  --eddi-shadow: rgba(0, 72, 128, .16);
  --eddi-drop: #4ea6e3;
  --eddi-drop-light: #a9d6f5;
  --eddi-drop-ring: rgba(0, 104, 177, .28);
  --eddi-bubble: #b5daf5;
  --eddi-bubble-shine: #ffffff;
  --eddi-thought: #ffffff;
  --eddi-thought-rim: #9ccbee;
  --eddi-spark-a: #f4b331;
  --eddi-spark-c: #4ea6e3;

  /* Accessories: two or three tones each, like the body. */
  --eddi-a-red: #d7393a;
  --eddi-a-red-dark: #a92630;
  --eddi-a-white: #ffffff;
  --eddi-a-white-shade: #d7e2ec;
  --eddi-a-navy: #1d2f4f;
  --eddi-a-navy-dark: #132240;
  --eddi-a-navy-light: #2e4672;
  --eddi-a-black: #12171d;
  --eddi-a-gold: #f2b631;
  --eddi-a-gold-dark: #c98d12;
  --eddi-a-coral-dark: #cc4a3e;
  --eddi-a-pink: #f49ac1;
  --eddi-a-pink-dark: #d96b9c;
  --eddi-a-green: #3f9a5a;
  --eddi-a-green-dark: #2a7442;
  --eddi-a-cream: #fbf3e1;
  --eddi-a-cream-dark: #e2d2b0;
  --eddi-a-yellow: #ffd23f;
  --eddi-a-yellow-dark: #e2a71b;
  --eddi-a-purple: #6b4aa8;
  --eddi-a-purple-dark: #4a317f;
  --eddi-a-orange: #f3902c;
  --eddi-a-lens: #14243a;
  --eddi-a-glint: rgba(255, 255, 255, .5);
}

/* Dark: the same character, one step lighter so the blue still reads on
   the dark page ground and the belly does not glow. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --eddi-body: #1b7fc6;
    --eddi-body-shade: #0f63a2;
    --eddi-body-light: #52a8e6;
    --eddi-spot: #72baec;
    --eddi-fin: #146aa9;
    --eddi-fin-light: #4199dc;
    --eddi-tail-light: #2785ca;
    --eddi-pec: #4ca3e3;
    --eddi-pec-light: #83c3f0;
    --eddi-coral: #ff9a88;
    --eddi-coral-deep: #f07a6c;
    --eddi-belly: #dbe8f3;
    --eddi-belly-shade: #a3c1da;
    --eddi-eye-white: #f5f9fc;
    --eddi-pupil: #0b1b2b;
    --eddi-shine: #ffffff;
    --eddi-brow: #0a2f4f;
    --eddi-mouth: #0b1b2b;
    --eddi-shadow: rgba(0, 0, 0, .45);
    --eddi-drop: #5aaee6;
    --eddi-drop-light: #a8d4f2;
    --eddi-drop-ring: rgba(88, 174, 222, .32);
    --eddi-bubble: #7fb9e4;
    --eddi-bubble-shine: #ffffff;
    --eddi-thought: #e7f1f9;
    --eddi-thought-rim: #5d9fd3;
    --eddi-spark-a: #f2bb45;
    --eddi-spark-c: #6cb8ec;

    --eddi-a-red: #e0514f;
    --eddi-a-red-dark: #b5383a;
    --eddi-a-white: #eef3f7;
    --eddi-a-white-shade: #c0cedb;
    --eddi-a-navy: #2a416a;
    --eddi-a-navy-dark: #1b2c4f;
    --eddi-a-navy-light: #3b5888;
    --eddi-a-black: #0b0f13;
    --eddi-a-gold: #eab43c;
    --eddi-a-gold-dark: #c18a1c;
    --eddi-a-coral-dark: #c95347;
    --eddi-a-pink: #e893b8;
    --eddi-a-pink-dark: #cc6c96;
    --eddi-a-green: #4caa67;
    --eddi-a-green-dark: #33804c;
    --eddi-a-cream: #ece3cf;
    --eddi-a-cream-dark: #c9b994;
    --eddi-a-yellow: #f4c93e;
    --eddi-a-yellow-dark: #cf9a20;
    --eddi-a-purple: #7d5cbc;
    --eddi-a-purple-dark: #573c90;
    --eddi-a-orange: #ee953c;
    --eddi-a-lens: #0c1724;
    --eddi-a-glint: rgba(255, 255, 255, .42);
  }
}

/* The explicit toggle, and a local scope for a dark surface in a light page
   (for example a dark hero card). Keep both dark blocks identical. */
:root[data-theme="dark"],
[data-eddi-theme="dark"] {
  --eddi-body: #1b7fc6;
  --eddi-body-shade: #0f63a2;
  --eddi-body-light: #52a8e6;
  --eddi-spot: #72baec;
  --eddi-fin: #146aa9;
  --eddi-fin-light: #4199dc;
  --eddi-tail-light: #2785ca;
  --eddi-pec: #4ca3e3;
  --eddi-pec-light: #83c3f0;
  --eddi-coral: #ff9a88;
  --eddi-coral-deep: #f07a6c;
  --eddi-belly: #dbe8f3;
  --eddi-belly-shade: #a3c1da;
  --eddi-eye-white: #f5f9fc;
  --eddi-pupil: #0b1b2b;
  --eddi-shine: #ffffff;
  --eddi-brow: #0a2f4f;
  --eddi-mouth: #0b1b2b;
  --eddi-shadow: rgba(0, 0, 0, .45);
  --eddi-drop: #5aaee6;
  --eddi-drop-light: #a8d4f2;
  --eddi-drop-ring: rgba(88, 174, 222, .32);
  --eddi-bubble: #7fb9e4;
  --eddi-bubble-shine: #ffffff;
  --eddi-thought: #e7f1f9;
  --eddi-thought-rim: #5d9fd3;
  --eddi-spark-a: #f2bb45;
  --eddi-spark-c: #6cb8ec;

  --eddi-a-red: #e0514f;
  --eddi-a-red-dark: #b5383a;
  --eddi-a-white: #eef3f7;
  --eddi-a-white-shade: #c0cedb;
  --eddi-a-navy: #2a416a;
  --eddi-a-navy-dark: #1b2c4f;
  --eddi-a-navy-light: #3b5888;
  --eddi-a-black: #0b0f13;
  --eddi-a-gold: #eab43c;
  --eddi-a-gold-dark: #c18a1c;
  --eddi-a-coral-dark: #c95347;
  --eddi-a-pink: #e893b8;
  --eddi-a-pink-dark: #cc6c96;
  --eddi-a-green: #4caa67;
  --eddi-a-green-dark: #33804c;
  --eddi-a-cream: #ece3cf;
  --eddi-a-cream-dark: #c9b994;
  --eddi-a-yellow: #f4c93e;
  --eddi-a-yellow-dark: #cf9a20;
  --eddi-a-purple: #7d5cbc;
  --eddi-a-purple-dark: #573c90;
  --eddi-a-orange: #ee953c;
  --eddi-a-lens: #0c1724;
  --eddi-a-glint: rgba(255, 255, 255, .42);
}

@media (max-width: 640px) {
  :root {
    --eddi-size: 56px;
    --eddi-gap: 8px;
  }
}

/* 2. Dock and button */

.eddi-dock {
  position: fixed;
  z-index: var(--eddi-z, 150);
  top: var(--eddi-top, 70vh);
  width: var(--eddi-size);
  height: var(--eddi-size);
  font-family: var(--font);
  transform: translate3d(var(--eddi-shift-x, 0px), var(--eddi-shift-y, 0px), 0);
}

.eddi-dock[hidden] { display: none; }
.eddi-dock[data-edge="left"] { left: max(var(--eddi-gap), env(safe-area-inset-left, 0px)); }
.eddi-dock[data-edge="right"] { right: max(var(--eddi-gap), env(safe-area-inset-right, 0px)); }
.eddi-dock.is-gliding { transition: transform 240ms cubic-bezier(.2, .8, .2, 1); }
.eddi-dock[data-state="drag"] { will-change: transform; }

.eddi-button {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: grab;
  touch-action: none; /* the pointer drags Eddi instead of scrolling the page */
  -webkit-tap-highlight-color: transparent;
}

.eddi-dock[data-state="drag"] .eddi-button { cursor: grabbing; }

.eddi-button:focus-visible {
  outline: 3px solid transparent;
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* 3. Drawing */

.eddi {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Eddi faces right. On the right edge he turns to face the content. */
.eddi-dock[data-edge="right"] .eddi { transform: scaleX(-1); }

/* Browsers ignore the HTML hidden attribute on SVG elements. */
.eddi [hidden] { display: none; }

.eddi-body,
.eddi-lid,
.eddi-blinklid-skin { fill: var(--eddi-body); }
.eddi-lash { fill: var(--eddi-pupil); }
.eddi-body-shade,
.eddi-gill { fill: var(--eddi-body-shade); }
.eddi-spot { fill: var(--eddi-spot); }
.eddi-belly { fill: var(--eddi-belly); }
.eddi-belly-shade { fill: var(--eddi-belly-shade); }
.eddi-fin-base,
.eddi-tail-base { fill: var(--eddi-fin); }
.eddi-fin-light { fill: var(--eddi-fin-light); }
.eddi-pec { fill: var(--eddi-pec); }
.eddi-pec-light { fill: var(--eddi-pec-light); }
.eddi-pec-tip { fill: var(--eddi-coral); }
.eddi-tail-light { fill: var(--eddi-tail-light); }
.eddi-fin-accent { fill: var(--eddi-coral); }
.eddi-eye-white { fill: var(--eddi-eye-white); }
.eddi-pupil-dot { fill: var(--eddi-pupil); }
.eddi-shine { fill: var(--eddi-shine); }
/* Cheeks stay fully opaque: a translucent coral over Amtsblau turns grey. */
.eddi-cheek { fill: var(--eddi-coral); }
.eddi-mouth-fill { fill: var(--eddi-mouth); }
.eddi-tongue { fill: var(--eddi-coral-deep); }
.eddi-shadow { fill: var(--eddi-shadow); }
.eddi-drop { fill: var(--eddi-drop); }
.eddi-drop-light { fill: var(--eddi-drop-light); }
.eddi-crest { fill: var(--eddi-drop); }
.eddi-drop-ring { fill: none; stroke: var(--eddi-drop-ring); stroke-width: 3; }
.eddi-bubble-ball { fill: var(--eddi-bubble); }
.eddi-bubble-shine { fill: var(--eddi-bubble-shine); }
.eddi-thought { fill: var(--eddi-thought); stroke: var(--eddi-thought-rim); stroke-width: 2.4; }
.eddi-thought-shine { fill: var(--eddi-thought-rim); }
.eddi-spark-a { fill: var(--eddi-spark-a); }
.eddi-spark-b { fill: var(--eddi-coral); }
.eddi-spark-c { fill: var(--eddi-spark-c); }

/* Strokes only where a confident round line is the shape itself: the
   forehead sheen, brows, closed eyes and closed mouths. */
.eddi-sheen,
.eddi-brow,
.eddi-closed,
.eddi-mouth-line {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.eddi-sheen { stroke: var(--eddi-body-light); stroke-width: 5; }
.eddi-brow { stroke: var(--eddi-brow); stroke-width: 5.2; }
.eddi-closed { stroke: var(--eddi-pupil); stroke-width: 4.4; }
.eddi-mouth-line { stroke: var(--eddi-mouth); stroke-width: 4.8; }

.eddi-a-red { fill: var(--eddi-a-red); }
.eddi-a-red-dark { fill: var(--eddi-a-red-dark); }
.eddi-a-white { fill: var(--eddi-a-white); }
.eddi-a-white-shade { fill: var(--eddi-a-white-shade); }
.eddi-a-navy { fill: var(--eddi-a-navy); }
.eddi-a-navy-dark { fill: var(--eddi-a-navy-dark); }
.eddi-a-navy-light { fill: var(--eddi-a-navy-light); }
.eddi-a-black { fill: var(--eddi-a-black); }
.eddi-a-gold { fill: var(--eddi-a-gold); }
.eddi-a-gold-dark { fill: var(--eddi-a-gold-dark); }
.eddi-a-coral { fill: var(--eddi-coral-deep); }
.eddi-a-coral-dark { fill: var(--eddi-a-coral-dark); }
.eddi-a-pink { fill: var(--eddi-a-pink); }
.eddi-a-pink-dark { fill: var(--eddi-a-pink-dark); }
.eddi-a-green { fill: var(--eddi-a-green); }
.eddi-a-green-dark { fill: var(--eddi-a-green-dark); }
.eddi-a-cream { fill: var(--eddi-a-cream); }
.eddi-a-cream-dark { fill: var(--eddi-a-cream-dark); }
.eddi-a-yellow { fill: var(--eddi-a-yellow); }
.eddi-a-yellow-dark { fill: var(--eddi-a-yellow-dark); }
.eddi-a-purple { fill: var(--eddi-a-purple); }
.eddi-a-purple-dark { fill: var(--eddi-a-purple-dark); }
.eddi-a-orange { fill: var(--eddi-a-orange); }
.eddi-a-lens { fill: var(--eddi-a-lens); }
.eddi-a-glint { fill: var(--eddi-a-glint); }
.eddi-a-frame {
  fill: none;
  stroke: var(--eddi-a-lens);
  stroke-width: 4;
  stroke-linecap: round;
}

/* 4. Pivots: absolute viewBox coordinates, stable when an accessory
      changes the bounding box of a group. */

.eddi-root,
.eddi-shadow,
.eddi-dip,
.eddi-float,
.eddi-fish,
.eddi-tail,
.eddi-fin-dorsal,
.eddi-fin-adipose,
.eddi-fin-anal,
.eddi-fin-pec,
.eddi-fin-wave,
.eddi-head,
.eddi-eye,
.eddi-eye-blink,
.eddi-blinklid,
.eddi-pupil,
.eddi-pupil-move,
.eddi-lid,
.eddi-cheek,
.eddi-brow,
.eddi-mouth,
.eddi-jaw,
.eddi-eyes-closed,
.eddi-eyes-happy,
.eddi-happy-near,
.eddi-happy-far,
.eddi-splash,
.eddi-drop-ring,
.eddi-think,
.eddi-air,
.eddi-sparkle { transform-box: view-box; }

.eddi-root { transform-origin: 112px 180px; }
.eddi-shadow { transform-origin: 114px 180px; }
.eddi-float { transform-origin: 115px 110px; }
.eddi-fish { transform-origin: 115px 160px; }
.eddi-tail { transform-origin: 62px 111px; }
.eddi-fin-dorsal { transform-origin: 96px 68px; }
.eddi-fin-adipose { transform-origin: 60px 94px; }
.eddi-fin-anal { transform-origin: 62px 128px; }
.eddi-fin-pec { transform-origin: 107px 128px; }
/* The waving fin turns about its root, which hides under the top right
   of the head. */
.eddi-fin-wave { transform-origin: 161px 84px; }
.eddi-head { transform-origin: 115px 110px; }
.eddi-eye-near,
.eddi-eye-near .eddi-eye-blink,
.eddi-eye-near .eddi-pupil { transform-origin: 130px 105px; }
.eddi-eye-far,
.eddi-eye-far .eddi-eye-blink,
.eddi-eye-far .eddi-pupil { transform-origin: 160px 103px; }
.eddi-eye-near .eddi-lid { transform-origin: 130px 83.6px; }
.eddi-eye-far .eddi-lid { transform-origin: 160px 83px; }
/* Upper blink lids grow down from the top of the eye, lower lids up from
   the bottom. */
.eddi-eye-near .eddi-blinklid { transform-origin: 130px 83.8px; }
.eddi-eye-far .eddi-blinklid { transform-origin: 160px 83.5px; }
.eddi-eye-near .eddi-blinklid-low { transform-origin: 130px 126.2px; }
.eddi-eye-far .eddi-blinklid-low { transform-origin: 160px 122.5px; }
.eddi-cheek-near { transform-origin: 121px 130.5px; }
.eddi-cheek-far { transform-origin: 171px 124.5px; }
.eddi-brow-near { transform-origin: 129px 79px; }
.eddi-brow-far { transform-origin: 158px 78px; }
.eddi-mouth { transform-origin: 152px 131px; }
.eddi-jaw { transform-origin: 152px 125.6px; }
.eddi-eyes-closed,
.eddi-eyes-happy { transform-origin: 143px 104px; }
.eddi-happy-near { transform-origin: 130px 104px; }
.eddi-happy-far { transform-origin: 160.5px 102px; }
.eddi-mouth-sleep .eddi-mouth-fill { transform-box: view-box; transform-origin: 153.35px 131.68px; }
.eddi-splash,
.eddi-drop-ring { transform-origin: 116px 176px; }
.eddi-think-1 { transform-origin: 104px 46px; }
.eddi-think-2 { transform-origin: 90px 32px; }
.eddi-think-3 { transform-origin: 70px 16px; }
.eddi-air-1 { transform-origin: 178px 112px; }
.eddi-air-2 { transform-origin: 184px 96px; --eddi-air-y: 16px; }
.eddi-air-3 { transform-origin: 179px 80px; --eddi-air-y: 32px; }
.eddi-air-4 { transform-origin: 46px 90px; }
.eddi-air-5 { transform-origin: 60px 64px; }
.eddi-sparkle-1 { transform-origin: 34px 48px; }
.eddi-sparkle-2 { transform-origin: 172px 30px; }
.eddi-sparkle-3 { transform-origin: 190px 88px; }
.eddi-sparkle-4 { transform-origin: 22px 128px; }
.eddi-sparkle-5 { transform-origin: 120px 18px; }

/* 5. Expression layer: always on, also under reduced motion.
      A state only sets the custom properties that differ from idle. */

.eddi-mouth {
  opacity: 0;
  transform: scale(.4);
  transition: opacity 120ms ease, transform 320ms var(--eddi-pop);
}
.eddi-mouth-smile { opacity: var(--eddi-m-smile, 1); transform: scale(calc(.4 + .6 * var(--eddi-m-smile, 1))); }
.eddi-mouth-grin { opacity: var(--eddi-m-grin, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-grin, 0))); }
.eddi-mouth-talk { opacity: var(--eddi-m-talk, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-talk, 0))); }
.eddi-mouth-o { opacity: var(--eddi-m-o, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-o, 0))); }
.eddi-mouth-wavy { opacity: var(--eddi-m-wavy, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-wavy, 0))); }
.eddi-mouth-hmm { opacity: var(--eddi-m-hmm, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-hmm, 0))); }
.eddi-mouth-smirk { opacity: var(--eddi-m-smirk, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-smirk, 0))); }
.eddi-mouth-sleep { opacity: var(--eddi-m-sleep, 0); transform: scale(calc(.4 + .6 * var(--eddi-m-sleep, 0))); }

/* Lids are body colored and grow from the eye edge. Where a lid pokes past
   the eye white during the transition it lies on the body and is invisible. */
.eddi-lid { transition: transform 260ms var(--eddi-soft); }
.eddi-lid-worry { transform: scaleY(var(--eddi-lid-worry, 0)); }
.eddi-lid-heavy { transform: scaleY(var(--eddi-lid-heavy, 0)); }
/* The blink lid rests at scaleY 0, folded into the top of the eye. Only
   the blink keyframes pull it down, so the eye white and pupil never
   squash into a slit. */
.eddi-blinklid { transform: scaleY(0); }

/* Each eye is clipped to its white plus a hair, the way a socket holds an
   eye: a half closed lid is as wide as the eye at its widest, and without
   the clip it pokes past the head outline above the far eye. Pupils that
   look far to one side stay inside the white for the same reason. Where a
   browser cannot clip SVG with a basic shape nothing changes. */
.eddi-eye-near .eddi-eye-blink { clip-path: ellipse(17.8px 20.8px at 130px 105px) view-box; }
.eddi-eye-far .eddi-eye-blink { clip-path: ellipse(14.3px 19.3px at 160px 103px) view-box; }

.eddi-eye {
  opacity: calc(1 - var(--eddi-eyes-closed, 0) - var(--eddi-eyes-happy, 0));
  transform: scale(var(--eddi-eye-scale, 1));
  transition: opacity 140ms ease, transform 300ms var(--eddi-pop);
}
/* A wink closes only the near eye. Opacity clamps at 0, so the sums are safe. */
.eddi-eye-near { opacity: calc(1 - var(--eddi-eyes-closed, 0) - var(--eddi-eyes-happy, 0) - var(--eddi-wink, 0)); }
.eddi-eyes-closed {
  opacity: var(--eddi-eyes-closed, 0);
  transition: opacity 140ms ease;
}
.eddi-happy-near,
.eddi-happy-far { transition: opacity 140ms ease, transform 320ms var(--eddi-pop); }
.eddi-happy-near {
  opacity: calc(var(--eddi-eyes-happy, 0) + var(--eddi-wink, 0));
  transform: scale(calc(.6 + .4 * min(1, var(--eddi-eyes-happy, 0) + var(--eddi-wink, 0))));
}
.eddi-happy-far {
  opacity: var(--eddi-eyes-happy, 0);
  transform: scale(calc(.6 + .4 * var(--eddi-eyes-happy, 0)));
}
.eddi-pupil {
  transform: var(--eddi-pupil, none);
  transition: transform 320ms var(--eddi-pop);
}
.eddi-brow { transition: transform 340ms var(--eddi-pop); }
.eddi-brow-near { transform: var(--eddi-brow-near, none); }
.eddi-brow-far { transform: var(--eddi-brow-far, none); }
/* Cheeks never fade: a state changes their size, not their opacity. */
.eddi-cheek {
  transform: scale(var(--eddi-cheek-scale, 1));
  transition: transform 320ms var(--eddi-pop);
}

/* Effects start invisible. Motion or the reduced pose reveals them. */
.eddi-splash,
.eddi-think,
.eddi-air,
.eddi-sparkle,
.eddi-fin-wave { opacity: 0; }

.eddi-dock[data-state="talk"] {
  --eddi-m-smile: 0;
  --eddi-m-talk: 1;
}

.eddi-dock[data-state="wave"] {
  --eddi-m-smile: 0;
  --eddi-m-grin: 1;
  --eddi-brow-near: translate(0, -2px);
  --eddi-brow-far: translate(0, -2px);
}

.eddi-dock:is([data-state="happy"], [data-state="celebrate"]) {
  --eddi-m-smile: 0;
  --eddi-m-grin: 1;
  --eddi-eyes-happy: 1;
  --eddi-cheek-scale: 1.18;
  --eddi-brow-near: translate(0, -3px) rotate(-4deg);
  --eddi-brow-far: translate(0, -3px) rotate(4deg);
}

/* celebrate laughs bigger than happy: the grin opens wider (the mouth
   scale reads the same property, opacity simply clamps at 1), the cheeks
   glow fuller and the brows jump higher. */
.eddi-dock[data-state="celebrate"] {
  --eddi-m-grin: 1.2;
  --eddi-cheek-scale: 1.28;
  --eddi-brow-near: translate(0, -5px) rotate(-6deg);
  --eddi-brow-far: translate(0, -5px) rotate(6deg);
}

/* leap shows on every finished task, so it has to read as proud joy at a
   glance: wide open eyes looking up and ahead toward where he jumps, brows
   raised with the inner ends up, a big open grin and full cheeks. Lowered
   lids or inner brow ends pushed down read as bored or sarcastic here, and
   open eyes keep it clearly different from the squint of happy. */
.eddi-dock[data-state="leap"] {
  --eddi-m-smile: 0;
  --eddi-m-grin: 1;
  --eddi-pupil: translate(3px, -3px);
  --eddi-cheek-scale: 1.2;
  --eddi-brow-near: translate(0, -4px) rotate(-5deg);
  --eddi-brow-far: translate(0, -4px) rotate(5deg);
}

/* look is a curious, slightly cheeky side glance: one brow up, a lopsided
   smile. The brow asymmetry and the mouth keep it apart from idle even at
   48 px, where the pupil travel alone is barely one pixel. */
.eddi-dock[data-state="look"] {
  --eddi-m-smile: 0;
  --eddi-m-smirk: 1;
  --eddi-brow-near: translate(0, -4px) rotate(-6deg);
  --eddi-brow-far: translate(0, .5px) rotate(2deg);
}

/* think: eyes up and back, one brow high, the other low and flat, the
   mouth pushed to one side. Together with the nose up tilt and the rising
   bubbles it is the most asymmetric face, so it reads at any size. */
.eddi-dock[data-state="think"] {
  --eddi-m-smile: 0;
  --eddi-m-hmm: 1;
  --eddi-pupil: translate(-3.5px, -7px);
  --eddi-brow-near: translate(0, -7px) rotate(-10deg);
  --eddi-brow-far: translate(-.5px, 2px) rotate(-3deg);
}

/* surprised: the biggest eyes with the smallest pupils, both brows high
   and an open O. The far brow also moves inward, so it stays inside the
   round head. */
.eddi-dock[data-state="surprised"] {
  --eddi-m-smile: 0;
  --eddi-m-o: 1;
  --eddi-eye-scale: 1.15;
  --eddi-pupil: scale(.6);
  --eddi-cheek-scale: .85;
  --eddi-brow-near: translate(0, -8px);
  --eddi-brow-far: translate(-3.5px, -5px) rotate(-6deg);
}

/* Concerned stays kind: worried brows and a small sigh, never a frown. */
.eddi-dock[data-state="concerned"] {
  --eddi-m-smile: 0;
  --eddi-m-wavy: 1;
  --eddi-lid-worry: 1;
  --eddi-pupil: translate(-1px, 2px);
  --eddi-brow-near: translate(1px, -1.5px) rotate(-13deg);
  --eddi-brow-far: translate(-1px, -1.5px) rotate(13deg);
  --eddi-cheek-scale: .8;
}

.eddi-dock[data-state="sleep"] {
  --eddi-m-smile: 0;
  --eddi-m-sleep: 1;
  --eddi-eyes-closed: 1;
  --eddi-brow-near: translate(0, 3px);
  --eddi-brow-far: translate(0, 3px);
}

.eddi-dock[data-state="drag"] {
  --eddi-m-smile: 0;
  --eddi-m-grin: 1;
  --eddi-eye-scale: 1.05;
  --eddi-brow-near: translate(0, -4px);
  --eddi-brow-far: translate(0, -4px);
}

/* dive says see you later: a wink with the near eye and a grin. */
.eddi-dock[data-state="dive"] {
  --eddi-m-smile: 0;
  --eddi-m-grin: 1;
  --eddi-wink: 1;
  --eddi-brow-far: translate(0, -2px);
}

.eddi-dock[data-state="surface"] {
  --eddi-brow-near: translate(0, -2px);
  --eddi-brow-far: translate(0, -2px);
}

/* 6. Motion layer */

/* Calm states share the hover float, the slow tail and the fin paddle. */
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"], [data-state="wave"]) .eddi-float {
  animation: eddi-float 3.6s var(--eddi-soft) infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"], [data-state="wave"]) .eddi-shadow {
  animation: eddi-shadow 3.6s var(--eddi-soft) infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"], [data-state="wave"],
              [data-state="surprised"], [data-state="happy"]) .eddi-tail {
  animation: eddi-tail 1.8s var(--eddi-soft) infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"]) .eddi-fin-pec {
  animation: eddi-paddle 1.8s var(--eddi-soft) -.45s infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"]) .eddi-fin-dorsal {
  animation: eddi-dorsal 3.6s var(--eddi-soft) infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="blink"], [data-state="look"],
              [data-state="talk"], [data-state="think"], [data-state="wave"]) .eddi-fin-adipose {
  animation: eddi-adipose 1.8s var(--eddi-soft) -.3s infinite;
}

/* idle: blink every 5 s, look around every 9 s. A blink is the lid coming
   down, not the eye squashing. */
.eddi-dock:is(:not([data-state]), [data-state="idle"], [data-state="talk"], [data-state="wave"],
              [data-state="think"], [data-state="swim"]) .eddi-blinklid {
  animation: eddi-blink 5.2s linear infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"]) .eddi-pupil-move {
  animation: eddi-look-around 9s var(--eddi-soft) infinite;
}
.eddi-dock:is(:not([data-state]), [data-state="idle"]) .eddi-head {
  animation: eddi-head-around 9s var(--eddi-soft) infinite;
}

/* blink: one double blink, about 0.7 s. */
.eddi-dock[data-state="blink"] .eddi-blinklid { animation: eddi-blink-twice 700ms linear 1; }
.eddi-dock[data-state="blink"] .eddi-float { animation: eddi-float 3.6s var(--eddi-soft) infinite, eddi-done 700ms linear 1; }

/* look: pupils left and right, the face turns with them a little. */
.eddi-dock[data-state="look"] .eddi-pupil-move { animation: eddi-look 3.4s var(--eddi-soft) infinite; }
.eddi-dock[data-state="look"] .eddi-head { animation: eddi-head-look 3.4s var(--eddi-soft) infinite; }
.eddi-dock[data-state="look"] .eddi-blinklid { animation: eddi-blink 3.4s linear -1.6s infinite; }

/* talk: the jaw opens and closes in an uneven rhythm, like speech. */
.eddi-dock[data-state="talk"] .eddi-jaw { animation: eddi-talk 1.1s linear infinite; }
.eddi-dock[data-state="talk"] .eddi-fin-pec { animation: eddi-gesture 2.2s var(--eddi-soft) infinite; }

/* wave: the far pectoral fin rises from behind the head, waves hello three
   times against the background and sinks back, 2.4 s per greeting. The
   near fin keeps paddling and the body leans back a little into the
   wave. Every cycle starts and ends with the fin hidden behind the head,
   so the script can leave wave at the end of a cycle without a pop. */
.eddi-dock[data-state="wave"] .eddi-fin-pec { animation: eddi-paddle 1.2s var(--eddi-soft) infinite; }
.eddi-dock[data-state="wave"] .eddi-fin-wave { animation: eddi-wave 2.4s linear infinite; }
.eddi-dock[data-state="wave"] .eddi-fin-dorsal { animation: eddi-dorsal 2.4s var(--eddi-soft) infinite; }
.eddi-dock[data-state="wave"] .eddi-fish { animation: eddi-lean 2.4s var(--eddi-soft) infinite; }

/* happy: a little hop with squash and stretch, 1 s. */
.eddi-dock[data-state="happy"] .eddi-float { animation: eddi-hop 1s linear 1 both; }
.eddi-dock[data-state="happy"] .eddi-fish { animation: eddi-squash 1s linear 1 both; }
.eddi-dock[data-state="happy"] .eddi-shadow { animation: eddi-shadow-hop 1s linear 1 both; }

/* leap: the proud salmon leap for a finished task, 1.6 s. */
.eddi-dock[data-state="leap"] .eddi-float { animation: eddi-leap 1.6s linear 1 both; }
.eddi-dock[data-state="leap"] .eddi-fish { animation: eddi-leap-squash 1.6s linear 1 both; }
.eddi-dock[data-state="leap"] .eddi-tail { animation: eddi-tail-fast .2s linear 8; }
.eddi-dock[data-state="leap"] .eddi-fin-pec { animation: eddi-fin-tuck 1.6s var(--eddi-soft) 1; }
.eddi-dock[data-state="leap"] .eddi-shadow { animation: eddi-shadow-leap 1.6s linear 1 both; }
.eddi-dock[data-state="leap"] .eddi-splash { animation: eddi-splash-twice 1.6s linear 1 both; }
.eddi-dock[data-state="leap"] .eddi-drop-ring { animation: eddi-ring-twice 1.6s linear 1 both; }

/* celebrate: all done. A crouch, a high hop with a full loop at the top,
   a landing, one small bounce, sparkles and bubbles, 2 s. The loop is a
   rotation in the picture plane, fast enough that the belly is up for
   only about 80 ms, so it reads as a joyful flip and never as the dead
   fish pose. No negative scaleX: that flattens a flat drawing into a
   paper cutout. Sparkles start on the take off and peak big. */
.eddi-dock[data-state="celebrate"] .eddi-float { animation: eddi-spin 2s linear 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-fish { animation: eddi-spin-squash 2s linear 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-fin-pec { animation: eddi-fin-pump 2s var(--eddi-soft) 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-tail { animation: eddi-tail-fast .2s linear 10; }
.eddi-dock[data-state="celebrate"] .eddi-shadow { animation: eddi-shadow-spin 2s linear 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle { animation: eddi-sparkle 1.1s var(--eddi-soft) 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle-1 { animation-delay: .1s; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle-2 { animation-delay: .22s; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle-3 { animation-delay: .34s; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle-4 { animation-delay: .46s; }
.eddi-dock[data-state="celebrate"] .eddi-sparkle-5 { animation-delay: .58s; }
.eddi-dock[data-state="celebrate"] .eddi-air { animation: eddi-rise 1.4s var(--eddi-soft) 1 both; }
.eddi-dock[data-state="celebrate"] .eddi-air-2 { animation-delay: .2s; }
.eddi-dock[data-state="celebrate"] .eddi-air-3 { animation-delay: .4s; }
.eddi-dock[data-state="celebrate"] .eddi-air-4 { animation-delay: .3s; }
.eddi-dock[data-state="celebrate"] .eddi-air-5 { animation-delay: .55s; }

/* think: eyes up, nose a little up, three bubbles rise one after another. */
.eddi-dock[data-state="think"] .eddi-float { animation: eddi-ponder 3.6s var(--eddi-soft) infinite; }
.eddi-dock[data-state="think"] .eddi-think { animation: eddi-think 3.6s var(--eddi-soft) infinite; }
.eddi-dock[data-state="think"] .eddi-think-2 { animation-delay: .25s; }
.eddi-dock[data-state="think"] .eddi-think-3 { animation-delay: .5s; }

/* surprised: eyes wide and a small jump back, 0.8 s. */
.eddi-dock[data-state="surprised"] .eddi-float { animation: eddi-startle .8s linear 1 both; }
.eddi-dock[data-state="surprised"] .eddi-fin-pec { animation: eddi-flare .8s var(--eddi-soft) 1 both; }

/* concerned: a slow sigh with one small bubble, used gently for overdue tasks. */
.eddi-dock[data-state="concerned"] .eddi-float { animation: eddi-sigh 4.2s var(--eddi-soft) infinite; }
.eddi-dock[data-state="concerned"] .eddi-tail { animation: eddi-tail 3s var(--eddi-soft) infinite; }
.eddi-dock[data-state="concerned"] .eddi-fin-pec { animation: eddi-droop 4.2s var(--eddi-soft) infinite; }
.eddi-dock[data-state="concerned"] .eddi-air-1 { animation: eddi-sigh-bubble 4.2s var(--eddi-soft) infinite; }
.eddi-dock[data-state="concerned"] .eddi-blinklid { animation: eddi-blink 4.2s linear -2s infinite; }

/* sleep: eyes closed, slow breathing, bubbles drift up. */
.eddi-dock[data-state="sleep"] .eddi-float { animation: eddi-doze 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-fish { animation: eddi-breathe 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-tail { animation: eddi-tail 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-fin-pec { animation: eddi-paddle 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-mouth-sleep .eddi-mouth-fill { animation: eddi-snore 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-air-1,
.eddi-dock[data-state="sleep"] .eddi-air-2,
.eddi-dock[data-state="sleep"] .eddi-air-3 { animation: eddi-drift 5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="sleep"] .eddi-air-2 { animation-delay: 1.6s; }
.eddi-dock[data-state="sleep"] .eddi-air-3 { animation-delay: 3.2s; }

/* drag: fast tail wiggle and a wobble while the pointer holds Eddi. */
.eddi-dock[data-state="drag"] .eddi-float { animation: eddi-wobble .5s var(--eddi-soft) infinite; }
.eddi-dock[data-state="drag"] .eddi-tail { animation: eddi-tail-fast .22s linear infinite; }
.eddi-dock[data-state="drag"] .eddi-fin-pec { animation: eddi-paddle .44s var(--eddi-soft) infinite; }
.eddi-dock[data-state="drag"] .eddi-fin-adipose { animation: eddi-adipose .44s var(--eddi-soft) infinite; }

/* swim: gliding to another corner. */
.eddi-dock[data-state="swim"] .eddi-float { animation: eddi-swim 1.2s var(--eddi-soft) infinite; }
.eddi-dock[data-state="swim"] .eddi-tail { animation: eddi-tail-swim .6s var(--eddi-soft) infinite; }
.eddi-dock[data-state="swim"] .eddi-fin-pec { animation: eddi-paddle .6s var(--eddi-soft) infinite; }
.eddi-dock[data-state="swim"] .eddi-fin-dorsal { animation: eddi-dorsal 1.2s var(--eddi-soft) infinite; }

/* dive and surface cut Eddi at the water line (y 176, under the crest), so
   he slides into the water instead of turning see through. A static clip
   on the wrapper, not animated. Where a browser cannot clip SVG with a
   basic shape, the late opacity fade in the keyframes still hides him. */
.eddi-dock:is([data-state="dive"], [data-state="surface"]) .eddi-dip {
  clip-path: polygon(-50% -50%, 150% -50%, 150% 88%, -50% 88%) view-box;
}

/* dive: exit downward into a splash, 1.1 s, keeps the last frame. */
.eddi-dock[data-state="dive"] .eddi-float { animation: eddi-dive 1.1s linear 1 forwards; }
.eddi-dock[data-state="dive"] .eddi-tail { animation: eddi-tail-fast .22s linear 5; }
.eddi-dock[data-state="dive"] .eddi-fin-pec { animation: eddi-fin-tuck 1.1s var(--eddi-soft) 1; }
.eddi-dock[data-state="dive"] .eddi-shadow { animation: eddi-shadow-out 1.1s linear 1 forwards; }
.eddi-dock[data-state="dive"] .eddi-splash { animation: eddi-splash-dive 1.1s linear 1 both; }
.eddi-dock[data-state="dive"] .eddi-drop-ring { animation: eddi-ring-dive 1.1s linear 1 both; }

/* surface: enter from below through a splash, 1 s. */
.eddi-dock[data-state="surface"] .eddi-float { animation: eddi-surface 1s linear 1 both; }
.eddi-dock[data-state="surface"] .eddi-tail { animation: eddi-tail-fast .2s linear 5; }
.eddi-dock[data-state="surface"] .eddi-shadow { animation: eddi-shadow-in 1s linear 1 both; }
.eddi-dock[data-state="surface"] .eddi-splash { animation: eddi-splash-surface 1s linear 1 both; }
.eddi-dock[data-state="surface"] .eddi-drop-ring { animation: eddi-ring-surface 1s linear 1 both; }

/* 7. Keyframes */

/* An empty animation that only marks the end of a one shot state. */
@keyframes eddi-done { from { opacity: 1; } to { opacity: 1; } }

@keyframes eddi-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-4px); }
}

@keyframes eddi-shadow {
  0%, 100% { transform: scaleX(1); opacity: 1; }
  50% { transform: scaleX(.9); opacity: .7; }
}

/* The tail sways by rotation only. A horizontal squeeze at swim speed
   makes the tail visibly shrink and grow, which reads as a rubber stamp
   and not as a fin. */
@keyframes eddi-tail {
  0%, 100% { transform: rotate(-6deg); }
  50% { transform: rotate(6deg); }
}

@keyframes eddi-tail-swim {
  0%, 100% { transform: rotate(-12deg); }
  50% { transform: rotate(12deg); }
}

@keyframes eddi-tail-fast {
  0%, 100% { transform: rotate(-16deg); }
  50% { transform: rotate(16deg); }
}

@keyframes eddi-paddle {
  0%, 100% { transform: rotate(-7deg); }
  50% { transform: rotate(10deg); }
}

@keyframes eddi-dorsal {
  0%, 100% { transform: rotate(-3deg); }
  50% { transform: rotate(2deg); }
}

@keyframes eddi-adipose {
  0%, 100% { transform: rotate(-7deg); }
  50% { transform: rotate(6deg); }
}

/* The lid drops fast (ease in), rests closed for a moment and lifts a
   little slower (ease out), like a real blink. */
@keyframes eddi-blink {
  0%, 91.5% { transform: scaleY(0); animation-timing-function: cubic-bezier(.5, 0, .9, .6); }
  94% { transform: scaleY(1); }
  95.4% { transform: scaleY(1); animation-timing-function: cubic-bezier(.2, .6, .4, 1); }
  98.6%, 100% { transform: scaleY(0); }
}

@keyframes eddi-blink-twice {
  0% { transform: scaleY(0); animation-timing-function: cubic-bezier(.5, 0, .9, .6); }
  14% { transform: scaleY(1); }
  20% { transform: scaleY(1); animation-timing-function: cubic-bezier(.2, .6, .4, 1); }
  36% { transform: scaleY(0); animation-timing-function: cubic-bezier(.5, 0, .9, .6); }
  50% { transform: scaleY(1); }
  56% { transform: scaleY(1); animation-timing-function: cubic-bezier(.2, .6, .4, 1); }
  76%, 100% { transform: scaleY(0); }
}

@keyframes eddi-look-around {
  0%, 56%, 100% { transform: translate(0, 0); }
  60%, 68% { transform: translate(-4.5px, .5px); }
  72%, 80% { transform: translate(3px, -1.5px); }
  86% { transform: translate(0, 0); }
}

@keyframes eddi-head-around {
  0%, 56%, 100% { transform: translate(0, 0); }
  60%, 68% { transform: translate(-1.6px, 0); }
  72%, 80% { transform: translate(1.2px, 0); }
  86% { transform: translate(0, 0); }
}

/* Back far, forward only a little: the far pupil already sits near the
   front edge of its eye and must not leave the white. */
@keyframes eddi-look {
  0%, 100% { transform: translate(0, 0); }
  12%, 40% { transform: translate(-6.4px, .5px); }
  52%, 82% { transform: translate(2px, -1.5px); }
}

@keyframes eddi-head-look {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  12%, 40% { transform: translate(-2.6px, 0) rotate(-2deg); }
  52%, 82% { transform: translate(1.6px, 0) rotate(1.5deg); }
}

@keyframes eddi-talk {
  0%, 100% { transform: scaleY(.25); }
  10% { transform: scaleY(1); }
  20% { transform: scaleY(.45); }
  32% { transform: scaleY(.9); }
  44% { transform: scaleY(.2); }
  56% { transform: scaleY(.75); }
  66% { transform: scaleY(.35); }
  80% { transform: scaleY(1); }
  90% { transform: scaleY(.5); }
}

@keyframes eddi-gesture {
  0%, 100% { transform: rotate(-4deg); }
  30% { transform: rotate(22deg); }
  55% { transform: rotate(6deg); }
  75% { transform: rotate(16deg); }
}

/* The waving fin slides up out of the head along its own axis with a
   little overshoot, swings about its root between -6 and 18 degrees, one
   beat every 290 ms, which reads as a hand at any size, and slides back
   down. translate(-16px, 46px) pulls the whole fin inside the silhouette
   of the head, so it never needs to fade: it stays fully opaque and the
   head covers it. A half transparent fin looked like a ghost. */
@keyframes eddi-wave {
  0% { opacity: 1; transform: translate(-16px, 46px) rotate(0deg); animation-timing-function: cubic-bezier(.25, .9, .35, 1.2); }
  14% { transform: translate(0px, 0px) rotate(-6deg); animation-timing-function: var(--eddi-soft); }
  26% { transform: translate(0px, 0px) rotate(18deg); animation-timing-function: var(--eddi-soft); }
  38% { transform: translate(0px, 0px) rotate(-6deg); animation-timing-function: var(--eddi-soft); }
  50% { transform: translate(0px, 0px) rotate(18deg); animation-timing-function: var(--eddi-soft); }
  62% { transform: translate(0px, 0px) rotate(-6deg); animation-timing-function: var(--eddi-soft); }
  74% { transform: translate(0px, 0px) rotate(14deg); animation-timing-function: var(--eddi-soft); }
  80% { transform: translate(0px, 0px) rotate(4deg); animation-timing-function: cubic-bezier(.55, 0, .9, .5); }
  92%, 100% { opacity: 1; transform: translate(-16px, 46px) rotate(0deg); }
}

@keyframes eddi-lean {
  0%, 100% { transform: rotate(0deg); }
  14%, 74% { transform: rotate(-3deg); }
  92% { transform: rotate(0deg); }
}

@keyframes eddi-hop {
  0% { transform: translate(0, 0); animation-timing-function: var(--eddi-soft); }
  18% { transform: translate(0, 3px); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  46% { transform: translate(0, -26px) rotate(-6deg); animation-timing-function: cubic-bezier(.6, 0, .8, .4); }
  70% { transform: translate(0, 0) rotate(0deg); animation-timing-function: var(--eddi-soft); }
  82% { transform: translate(0, -4px); animation-timing-function: var(--eddi-soft); }
  100% { transform: translate(0, 0); }
}

@keyframes eddi-squash {
  0%, 100% { transform: scale(1, 1); }
  18% { transform: scale(1.1, .88); animation-timing-function: var(--eddi-pop); }
  38% { transform: scale(.93, 1.09); }
  60% { transform: scale(1, 1); }
  70% { transform: scale(1.1, .9); animation-timing-function: var(--eddi-pop); }
  84% { transform: scale(.98, 1.02); }
}

@keyframes eddi-shadow-hop {
  0%, 100% { transform: scaleX(1); opacity: 1; }
  46% { transform: scaleX(.66); opacity: .45; }
  70% { transform: scaleX(1.06); opacity: 1; }
}

/* Leap: dip, rise nose up, level out at the top, dive back nose down. */
@keyframes eddi-leap {
  0% { transform: translate(0, 0) rotate(0deg); animation-timing-function: var(--eddi-soft); }
  12% { transform: translate(0, 7px) rotate(5deg); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  42% { transform: translate(4px, -64px) rotate(-24deg); animation-timing-function: linear; }
  56% { transform: translate(10px, -74px) rotate(0deg); animation-timing-function: cubic-bezier(.5, 0, .9, .5); }
  80% { transform: translate(13px, -12px) rotate(30deg); animation-timing-function: cubic-bezier(.2, .6, .4, 1); }
  89% { transform: translate(6px, 6px) rotate(8deg); animation-timing-function: var(--eddi-pop); }
  100% { transform: translate(0, 0) rotate(0deg); }
}

@keyframes eddi-leap-squash {
  0%, 100% { transform: scale(1, 1); }
  12% { transform: scale(1.08, .9); }
  24% { transform: scale(.92, 1.1); }
  50% { transform: scale(1, 1); }
  89% { transform: scale(1.08, .92); }
}

@keyframes eddi-fin-tuck {
  0%, 100% { transform: rotate(0deg); }
  20%, 70% { transform: rotate(-22deg); }
}

@keyframes eddi-shadow-leap {
  0%, 100% { transform: scaleX(1); opacity: 1; }
  12% { transform: scaleX(1.06); opacity: 1; }
  56% { transform: scaleX(.42); opacity: .3; }
  89% { transform: scaleX(1.1); opacity: 1; }
}

@keyframes eddi-splash-twice {
  0%, 6% { opacity: 0; transform: translateY(6px) scale(.3, .2); }
  14% { opacity: 1; transform: translateY(0) scale(1, 1); }
  28%, 80% { opacity: 0; transform: translateY(-8px) scale(1.15, 1.2); }
  81% { opacity: 0; transform: translateY(6px) scale(.3, .2); }
  90% { opacity: 1; transform: translateY(0) scale(1, 1); }
  100% { opacity: 0; transform: translateY(-8px) scale(1.15, 1.2); }
}

@keyframes eddi-ring-twice {
  0%, 8% { opacity: 0; transform: scale(.4); }
  14% { opacity: 1; transform: scale(.7); }
  34%, 84% { opacity: 0; transform: scale(1.3); }
  85% { opacity: 0; transform: scale(.4); }
  90% { opacity: 1; transform: scale(.7); }
  100% { opacity: 0; transform: scale(1.3); }
}

/* The loop of celebrate: crouch, a high hop nose up, a fast full turn
   backward over the top (linear, 280 ms for 300 degrees, so the belly is
   up for about 80 ms), land on the overshoot, one small bounce nose down,
   settle. The rotation is carried as -360 degrees after the loop, so the
   bounce never unwinds it. The pivot is the middle of the fish (115 110),
   so he turns on the spot and not around his chin. */
@keyframes eddi-spin {
  0% { transform: translate(0, 0) rotate(0deg); animation-timing-function: var(--eddi-soft); }
  12% { transform: translate(0, 6px) rotate(3deg); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  26% { transform: translate(0, -48px) rotate(-30deg); animation-timing-function: linear; }
  40% { transform: translate(0, -54px) rotate(-330deg); animation-timing-function: cubic-bezier(.5, 0, .9, .5); }
  50% { transform: translate(0, 0) rotate(-360deg); animation-timing-function: var(--eddi-pop); }
  60% { transform: translate(0, -22px) rotate(-350deg); animation-timing-function: cubic-bezier(.6, 0, .9, .5); }
  76% { transform: translate(0, 0) rotate(-360deg); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  88% { transform: translate(0, -3px) rotate(-364deg); animation-timing-function: var(--eddi-soft); }
  100% { transform: translate(0, 0) rotate(-360deg); }
}

/* Squash on every contact with the ground, stretch on every take off and
   just before landing. scaleX stays between .92 and 1.12, never negative. */
@keyframes eddi-spin-squash {
  0%, 100% { transform: scale(1, 1); }
  12% { transform: scale(1.1, .88); }
  20% { transform: scale(.92, 1.1); }
  28% { transform: scale(1, 1); }
  45% { transform: scale(.96, 1.05); }
  50% { transform: scale(1.12, .86); animation-timing-function: var(--eddi-pop); }
  56% { transform: scale(.94, 1.07); }
  64% { transform: scale(1, 1); }
  72% { transform: scale(.97, 1.04); }
  76% { transform: scale(1.1, .9); animation-timing-function: var(--eddi-pop); }
  86% { transform: scale(.98, 1.02); }
}

/* The pectoral fin pumps down on the push, tucks in for the loop, and
   pumps once more on the bounce. */
@keyframes eddi-fin-pump {
  0%, 76%, 100% { transform: rotate(0deg); }
  14% { transform: rotate(-40deg); }
  24%, 42% { transform: rotate(-24deg); }
  50% { transform: rotate(-35deg); }
  60% { transform: rotate(20deg); }
}

@keyframes eddi-shadow-spin {
  0%, 100% { transform: scaleX(1); opacity: 1; }
  12% { transform: scaleX(1.06); opacity: 1; }
  26%, 40% { transform: scaleX(.45); opacity: .35; }
  50% { transform: scaleX(1.08); opacity: 1; }
  60% { transform: scaleX(.72); opacity: .6; }
  76% { transform: scaleX(1.06); opacity: 1; }
}

/* Sparkles pop to 1.4 times their size with the overshoot, then twinkle
   out while they turn. */
@keyframes eddi-sparkle {
  0% { opacity: 0; transform: scale(0) rotate(-40deg); animation-timing-function: var(--eddi-pop); }
  30% { opacity: 1; transform: scale(1.4) rotate(0deg); animation-timing-function: var(--eddi-soft); }
  60% { opacity: 1; transform: scale(1) rotate(12deg); }
  100% { opacity: 0; transform: scale(.2) rotate(30deg); }
}

@keyframes eddi-rise {
  0% { opacity: 0; transform: translate(0, 24px) scale(.4); }
  25% { opacity: .95; }
  100% { opacity: 0; transform: translate(4px, -40px) scale(1.1); }
}

@keyframes eddi-ponder {
  0%, 100% { transform: translateY(0) rotate(-7deg); }
  50% { transform: translateY(-3px) rotate(-9deg); }
}

@keyframes eddi-think {
  0% { opacity: 0; transform: translateY(6px) scale(.2); animation-timing-function: var(--eddi-pop); }
  14% { opacity: 1; transform: translateY(0) scale(1); }
  50% { transform: translateY(-2px) scale(1.03); }
  80% { opacity: 1; transform: translateY(0) scale(1); }
  94%, 100% { opacity: 0; transform: translateY(-6px) scale(.9); }
}

@keyframes eddi-startle {
  0% { transform: translate(0, 0) rotate(0deg); animation-timing-function: cubic-bezier(.2, .9, .3, 1); }
  22% { transform: translate(-11px, -12px) rotate(-10deg); animation-timing-function: var(--eddi-soft); }
  52% { transform: translate(-6px, 2px) rotate(-2deg); animation-timing-function: var(--eddi-pop); }
  100% { transform: translate(0, 0) rotate(0deg); }
}

@keyframes eddi-flare {
  0%, 100% { transform: rotate(0deg); }
  20%, 60% { transform: rotate(-24deg); }
}

@keyframes eddi-sigh {
  0%, 30%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
  42% { transform: translateY(-3px) rotate(-1deg) scale(1.02); }
  64% { transform: translateY(3px) rotate(3deg) scale(.99); }
  86% { transform: translateY(1px) rotate(1.5deg) scale(1); }
}

@keyframes eddi-droop {
  0%, 30%, 100% { transform: rotate(8deg); }
  64% { transform: rotate(18deg); }
}

@keyframes eddi-sigh-bubble {
  0%, 56% { opacity: 0; transform: translate(-4px, 14px) scale(.4); }
  64% { opacity: .95; transform: translate(-2px, 6px) scale(.8); }
  92%, 100% { opacity: 0; transform: translate(2px, -18px) scale(1); }
}

@keyframes eddi-doze {
  0%, 100% { transform: translateY(0) rotate(4deg); }
  50% { transform: translateY(2px) rotate(5deg); }
}

@keyframes eddi-breathe {
  0%, 100% { transform: scale(1, 1); }
  50% { transform: scale(1.015, 1.03); }
}

@keyframes eddi-snore {
  0%, 100% { transform: scale(.8); }
  50% { transform: scale(1.12); }
}

/* The three sleep bubbles rest at different heights (the reduced pose), so
   each one starts from the mouth through its own --eddi-air-y offset. */
@keyframes eddi-drift {
  0% { opacity: 0; transform: translate(-4px, calc(16px + var(--eddi-air-y, 0px))) scale(.4); }
  15% { opacity: .9; }
  70% { opacity: .7; }
  100% { opacity: 0; transform: translate(6px, calc(-44px + var(--eddi-air-y, 0px))) scale(1.1); }
}

@keyframes eddi-wobble {
  0%, 100% { transform: translateY(0) rotate(-4deg); }
  50% { transform: translateY(-2px) rotate(4deg); }
}

@keyframes eddi-swim {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50% { transform: translateY(-3px) rotate(1deg); }
}

/* Dive: a small hop nose up, then nose first through the crest. The nose
   meets the water line at 44 percent and the clip on .eddi-dip swallows
   him from there. By 100 percent every part, hats included, is below the
   water line. The opacity fade at the very end only matters where the
   clip is not supported. */
@keyframes eddi-dive {
  0% { transform: translate(0, 0) rotate(0deg); opacity: 1; animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  20% { transform: translate(-4px, -16px) rotate(-16deg); opacity: 1; animation-timing-function: cubic-bezier(.5, 0, .9, .6); }
  44% { transform: translate(-6px, 10px) rotate(62deg); opacity: 1; animation-timing-function: linear; }
  72% { transform: translate(-10px, 96px) rotate(76deg); opacity: 1; }
  90% { transform: translate(-13px, 160px) rotate(79deg); opacity: 1; }
  100% { transform: translate(-14px, 190px) rotate(80deg); opacity: 0; }
}

@keyframes eddi-shadow-out {
  0%, 30% { transform: scaleX(1); opacity: 1; }
  60% { transform: scaleX(1.15); opacity: .8; }
  100% { transform: scaleX(.6); opacity: 0; }
}

/* The crest has to stand until the last fin is under (about 95 percent). */
@keyframes eddi-splash-dive {
  0%, 38% { opacity: 0; transform: translateY(6px) scale(.3, .2); }
  48% { opacity: 1; transform: translateY(0) scale(1, 1); animation-timing-function: var(--eddi-soft); }
  92% { opacity: 1; transform: translateY(-4px) scale(1.1, 1.12); }
  100% { opacity: 0; transform: translateY(-6px) scale(1.14, 1.16); }
}

@keyframes eddi-ring-dive {
  0%, 42% { opacity: 0; transform: scale(.4); }
  52% { opacity: 1; transform: scale(.75); }
  100% { opacity: 0; transform: scale(1.4); }
}

/* Surface: up through the crest nose first, overshoot, settle. He starts
   fully below the water line, the clip on .eddi-dip hides him there. */
@keyframes eddi-surface {
  0% { transform: translate(10px, 186px) rotate(-64deg); opacity: 0; }
  6% { transform: translate(9px, 160px) rotate(-62deg); opacity: 1; animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  42% { transform: translate(0, -22px) rotate(-8deg); opacity: 1; animation-timing-function: cubic-bezier(.5, 0, .7, .5); }
  64% { transform: translate(0, 4px) rotate(3deg); animation-timing-function: var(--eddi-pop); }
  100% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
}

@keyframes eddi-shadow-in {
  0%, 20% { transform: scaleX(.4); opacity: 0; }
  76% { transform: scaleX(1.1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 1; }
}

@keyframes eddi-splash-surface {
  0% { opacity: 0; transform: translateY(6px) scale(.3, .2); }
  12% { opacity: 1; transform: translateY(0) scale(1, 1); }
  34% { opacity: 1; transform: translateY(-6px) scale(1.12, 1.16); }
  60%, 100% { opacity: 0; transform: translateY(-10px) scale(1.2, 1.25); }
}

@keyframes eddi-ring-surface {
  0%, 10% { opacity: 0; transform: scale(.4); }
  24% { opacity: 1; transform: scale(.75); }
  70%, 100% { opacity: 0; transform: scale(1.4); }
}

@keyframes eddi-bubble-in {
  from { opacity: 0; transform: translateY(4px) scale(.96); }
  to { opacity: 1; transform: none; }
}

/* 8. Seasonal skins */

/* base.css hides [hidden] with !important, so a skin needs !important plus
   a more specific selector to show its group. The hidden attribute stays in
   the drawing, so without eddi.css no accessory ever shows. */
.eddi-dock[data-skin="captain"] .eddi-acc-captain,
.eddi-dock[data-skin="christmas"] .eddi-acc-santa,
.eddi-dock[data-skin="christmas"] .eddi-acc-scarf,
.eddi-dock[data-skin="new-year"] .eddi-acc-party,
.eddi-dock[data-skin="easter"] .eddi-acc-bunny,
.eddi-dock[data-skin="spring"] .eddi-acc-flowers,
.eddi-dock[data-skin="kieler-woche"] .eddi-acc-sailor,
.eddi-dock[data-skin="summer"] .eddi-acc-shades,
.eddi-dock[data-skin="rain"] .eddi-acc-rain,
.eddi-dock[data-skin="halloween"] .eddi-acc-witch,
.eddi-dock[data-skin="advent"] .eddi-acc-beanie,
.eddi-dock[data-skin="winter"] .eddi-acc-beanie,
.eddi-dock[data-skin="winter"] .eddi-acc-scarf { display: inline !important; }

/* 9. Speech bubble */

.eddi-bubble {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  box-sizing: border-box;
  width: max-content;
  max-width: min(300px, calc(100vw - 2 * var(--eddi-gap)));
  margin: 0;
  padding: 10px 44px 10px 14px; /* room for the close button */
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
  font: 400 .9375rem/1.45 var(--font);
  animation: eddi-bubble-in 180ms ease-out both;
}

.eddi-bubble[hidden] { display: none; }

/* The tail points at the mouth, which sits at about 76 percent of the width. */
.eddi-bubble::after {
  content: "";
  position: absolute;
  bottom: -7px;
  left: calc(var(--eddi-size) * .74 - 6px);
  width: 12px;
  height: 12px;
  background: var(--surface);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  transform: rotate(45deg);
}

.eddi-dock[data-edge="right"] .eddi-bubble { left: auto; right: 0; }
.eddi-dock[data-edge="right"] .eddi-bubble::after { left: auto; right: calc(var(--eddi-size) * .74 - 6px); }
.eddi-dock[data-v="top"] .eddi-bubble { bottom: auto; top: calc(100% + 10px); }
.eddi-dock[data-v="top"] .eddi-bubble::after { bottom: auto; top: -7px; transform: rotate(225deg); }

.eddi-bubble-text { margin: 0; }

.eddi-bubble-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* display: flex above would beat the browser's [hidden] rule. */
.eddi-bubble-actions[hidden] { display: none; }

.eddi-bubble-close {
  position: absolute;
  top: 0;
  right: 0;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}

.eddi-bubble-close:hover { color: var(--ink); }

.eddi-bubble-close:focus-visible {
  outline: 3px solid transparent;
  outline-offset: -3px;
  box-shadow: inset 0 0 0 3px var(--focus-ring);
}

/* 10. Options button */

/* Sits above the tail, away from the face and the bubble tail. */
.eddi-more {
  position: absolute;
  top: -12px;
  left: -12px;
  isolation: isolate;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  opacity: 0;
  transition: opacity 150ms ease;
}

.eddi-more::before {
  content: "";
  position: absolute;
  inset: 8px;
  z-index: -1;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow);
}

.eddi-dock[data-edge="right"] .eddi-more { left: auto; right: -12px; }

.eddi-dock:hover .eddi-more,
.eddi-dock:focus-within .eddi-more,
.eddi-more[aria-expanded="true"] { opacity: 1; }

@media (hover: none) {
  .eddi-more { opacity: 1; }
}

/* The ring hugs the visible circle, not the 44 px hit area. */
.eddi-more:focus-visible {
  outline: 3px solid transparent;
  outline-offset: -5px;
  border-radius: 50%;
  box-shadow: none;
}

.eddi-more:focus-visible::before { box-shadow: 0 0 0 3px var(--focus-ring); }

/* Visually hidden live region: announces sayings the person asked for. */
.eddi-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 11. Reduced motion: no animation, no transition, one calm pose per state.
       The states set the pose properties, both blocks below only read them. */

.eddi-dock[data-state="look"] {
  --eddi-pose-pupils: translate(-6px, .5px);
  --eddi-pose-head: translate(-2.4px, 0) rotate(-2deg);
}
.eddi-dock[data-state="talk"] { --eddi-pose-jaw: scaleY(.8); }
/* wave holds the raised hand: the far fin up behind the head, tipped
   forward toward the face, the body leaning back a little. */
.eddi-dock[data-state="wave"] {
  --eddi-pose-wave: 1;
  --eddi-pose-wave-fin: rotate(8deg);
  --eddi-pose-fish: rotate(-3deg);
}
.eddi-dock[data-state="happy"] { --eddi-pose-float: translate(0, -4px); }
.eddi-dock[data-state="leap"] {
  --eddi-pose-float: translate(4px, -12px) rotate(-16deg);
  --eddi-pose-pec: rotate(-20deg);
  --eddi-pose-splash: 1;
}
.eddi-dock[data-state="celebrate"] { --eddi-pose-sparkle: 1; }
.eddi-dock[data-state="think"] {
  --eddi-pose-float: rotate(-7deg);
  --eddi-pose-think: 1;
}
.eddi-dock[data-state="surprised"] {
  --eddi-pose-float: translate(-4px, -3px) rotate(-5deg);
  --eddi-pose-pec: rotate(-20deg);
}
.eddi-dock[data-state="concerned"] {
  --eddi-pose-float: translateY(2px) rotate(2deg);
  --eddi-pose-pec: rotate(14deg);
}
.eddi-dock[data-state="sleep"] {
  --eddi-pose-float: rotate(4deg);
  --eddi-pose-air: .85;
}
.eddi-dock[data-state="drag"] {
  --eddi-pose-float: rotate(-4deg);
  --eddi-pose-tail: rotate(12deg);
}
.eddi-dock[data-state="swim"] { --eddi-pose-tail: rotate(-9deg) scaleX(.94); }
/* Calm pose for dive: Eddi stays level beside his splash. A nose down
   still frame looks like a crash. */
.eddi-dock[data-state="dive"] { --eddi-pose-splash: 1; }
.eddi-dock[data-state="surface"] { --eddi-pose-splash: 1; }

@media (prefers-reduced-motion: reduce) {
  .eddi-dock,
  .eddi-dock * {
    animation: none !important;
    transition: none !important;
  }
  .eddi-float { transform: var(--eddi-pose-float, none); }
  .eddi-fish { transform: var(--eddi-pose-fish, none); }
  .eddi-tail { transform: var(--eddi-pose-tail, none); }
  .eddi-fin-pec { transform: var(--eddi-pose-pec, none); }
  .eddi-fin-wave {
    transform: var(--eddi-pose-wave-fin, none);
    opacity: var(--eddi-pose-wave, 0);
  }
  .eddi-head { transform: var(--eddi-pose-head, none); }
  .eddi-pupil-move { transform: var(--eddi-pose-pupils, none); }
  .eddi-jaw { transform: var(--eddi-pose-jaw, none); }
  .eddi-splash { opacity: var(--eddi-pose-splash, 0); }
  .eddi-think { opacity: var(--eddi-pose-think, 0); }
  .eddi-sparkle { opacity: var(--eddi-pose-sparkle, 0); }
  .eddi-air-1,
  .eddi-air-2,
  .eddi-air-3 { opacity: var(--eddi-pose-air, 0); }
}

html[data-motion="reduce"] .eddi-dock,
html[data-motion="reduce"] .eddi-dock * {
  animation: none !important;
  transition: none !important;
}
html[data-motion="reduce"] .eddi-float { transform: var(--eddi-pose-float, none); }
html[data-motion="reduce"] .eddi-fish { transform: var(--eddi-pose-fish, none); }
html[data-motion="reduce"] .eddi-tail { transform: var(--eddi-pose-tail, none); }
html[data-motion="reduce"] .eddi-fin-pec { transform: var(--eddi-pose-pec, none); }
html[data-motion="reduce"] .eddi-fin-wave {
  transform: var(--eddi-pose-wave-fin, none);
  opacity: var(--eddi-pose-wave, 0);
}
html[data-motion="reduce"] .eddi-head { transform: var(--eddi-pose-head, none); }
html[data-motion="reduce"] .eddi-pupil-move { transform: var(--eddi-pose-pupils, none); }
html[data-motion="reduce"] .eddi-jaw { transform: var(--eddi-pose-jaw, none); }
html[data-motion="reduce"] .eddi-splash { opacity: var(--eddi-pose-splash, 0); }
html[data-motion="reduce"] .eddi-think { opacity: var(--eddi-pose-think, 0); }
html[data-motion="reduce"] .eddi-sparkle { opacity: var(--eddi-pose-sparkle, 0); }
html[data-motion="reduce"] .eddi-air-1,
html[data-motion="reduce"] .eddi-air-2,
html[data-motion="reduce"] .eddi-air-3 { opacity: var(--eddi-pose-air, 0); }

/* 12. Small viewports, forced colors, print */

/* Phones, 400 percent zoom and very low windows leave no free corner. */
@media (max-width: 479.98px), (max-height: 479.98px) {
  .eddi-dock { display: none; }
}

@media (forced-colors: active) {
  /* Keep the system color mapping below instead of one forced color. */
  .eddi { forced-color-adjust: none; }
  .eddi-body,
  .eddi-fin-base,
  .eddi-tail-base,
  .eddi-pec,
  .eddi-thought,
  .eddi-eye-white,
  .eddi-a-red,
  .eddi-a-white,
  .eddi-a-navy,
  .eddi-a-gold,
  .eddi-a-coral,
  .eddi-a-pink,
  .eddi-a-green,
  .eddi-a-cream,
  .eddi-a-yellow,
  .eddi-a-purple,
  .eddi-a-orange { fill: Canvas; stroke: CanvasText; stroke-width: 1.5; }
  .eddi-lid,
  .eddi-blinklid-skin,
  .eddi-belly { fill: Canvas; }
  .eddi-pupil-dot,
  .eddi-lash,
  .eddi-mouth-fill,
  .eddi-a-black,
  .eddi-a-lens,
  .eddi-a-navy-dark { fill: CanvasText; }
  .eddi-shine { fill: Canvas; }
  .eddi-brow,
  .eddi-closed,
  .eddi-mouth-line,
  .eddi-a-frame { stroke: CanvasText; }
  .eddi-body-shade,
  .eddi-gill,
  .eddi-spot,
  .eddi-sheen,
  .eddi-belly-shade,
  .eddi-fin-light,
  .eddi-pec-light,
  .eddi-pec-tip,
  .eddi-fin-accent,
  .eddi-thought-shine,
  .eddi-tail-light,
  .eddi-cheek,
  .eddi-tongue,
  .eddi-shadow,
  .eddi-a-glint,
  .eddi-a-red-dark,
  .eddi-a-white-shade,
  .eddi-a-navy-light,
  .eddi-a-gold-dark,
  .eddi-a-coral-dark,
  .eddi-a-pink-dark,
  .eddi-a-green-dark,
  .eddi-a-cream-dark,
  .eddi-a-yellow-dark,
  .eddi-a-purple-dark { fill: none; stroke: none; }
  .eddi-sheen { stroke: none; }
  .eddi-bubble,
  .eddi-bubble::after,
  .eddi-more::before { border-color: CanvasText; }
}

@media print {
  .eddi-dock { display: none !important; }
}
