:root{--trip-color-hue:0deg;--trip-color-saturation:1;--trip-color-contrast:1;--trip-mlg:0;--trip-color-speed:8s}.trip-hallucination-layer{position:absolute;inset:0;z-index:25;overflow:hidden;pointer-events:none;isolation:isolate;opacity:var(--hallucination-visibility,0);transition:opacity .9s ease;filter:hue-rotate(var(--hallucination-hue,0deg)) saturate(var(--hallucination-saturation,1))}.trip-hallucination-layer>img,.trip-hallucination-layer>div{position:absolute;will-change:transform}.trip-hallucination-layer img{display:block;max-width:none}.trip-hallucination-layer [data-trip-stage]{opacity:var(--apparition-opacity,0)}
.trip-ghost-eye{left:4%;top:62%;width:clamp(80px,10vw,145px);transform:rotate(-14deg) scale(var(--hallucination-scale,1))}
/* Five complete Paint frames play only after every image has decoded. */
.trip-eye-art{aspect-ratio:2/1;isolation:isolate;filter:drop-shadow(5px 4px 0 var(--ink))}
.trip-eye-art img{filter:none;pointer-events:none}
.trip-eye-art>.trip-eye-frame{position:absolute;inset:0;display:block;width:100%;height:100%;opacity:0;animation-duration:4.8s;animation-timing-function:steps(1,end);animation-iteration-count:infinite;animation-play-state:paused}
.trip-eye-art>.trip-eye-frame-3{opacity:1}
.trip-active .trip-eye-ready>.trip-eye-frame{animation-play-state:running}
.trip-eye-ready>.trip-eye-frame-1{animation-name:eye-frame-left}
.trip-eye-ready>.trip-eye-frame-2{animation-name:eye-frame-mid-left}
.trip-eye-ready>.trip-eye-frame-3{animation-name:eye-frame-center}
.trip-eye-ready>.trip-eye-frame-4{animation-name:eye-frame-mid-right}
.trip-eye-ready>.trip-eye-frame-5{animation-name:eye-frame-right}
.trip-cosmic-procession>.process-eye{position:absolute}
/* Five deferred Paint cels keep the smoke character alive while it glances,
   blinks and exhales. The rest pose stays visible until every cel decodes. */
.trip-smoke-art{position:absolute;aspect-ratio:2/3;isolation:isolate;filter:drop-shadow(5px 4px 0 var(--ink))}
.trip-smoke-art>.trip-smoke-frame{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;opacity:0;animation-duration:5.8s;animation-timing-function:steps(1,end);animation-iteration-count:infinite;animation-play-state:paused;pointer-events:none;filter:none}
.trip-smoke-art>.trip-smoke-frame-1{opacity:1}
.trip-smoke-ready>.trip-smoke-frame-1{animation-name:smoke-frame-rest}
.trip-smoke-ready>.trip-smoke-frame-2{animation-name:smoke-frame-left}
.trip-smoke-ready>.trip-smoke-frame-3{animation-name:smoke-frame-blink}
.trip-smoke-ready>.trip-smoke-frame-4{animation-name:smoke-frame-right}
.trip-smoke-ready>.trip-smoke-frame-5{animation-name:smoke-frame-exhale}
body.tripping .trip-smoke-ready>.trip-smoke-frame{animation-play-state:running}
@keyframes smoke-frame-rest{0%,100%{opacity:1}18%{opacity:0}80%{opacity:1}}
@keyframes smoke-frame-left{0%,100%{opacity:0}18%{opacity:1}38%{opacity:0}}
@keyframes smoke-frame-blink{0%,100%{opacity:0}38%{opacity:1}42%{opacity:0}}
@keyframes smoke-frame-right{0%,100%{opacity:0}42%{opacity:1}66%{opacity:0}}
@keyframes smoke-frame-exhale{0%,100%{opacity:0}66%{opacity:1}80%{opacity:0}}
@keyframes eye-frame-left{0%,74%,100%{opacity:1}19%{opacity:0}}
@keyframes eye-frame-mid-left{0%,23%,74%,100%{opacity:0}19%,70%{opacity:1}}
@keyframes eye-frame-center{0%,27%,70%,100%{opacity:0}23%,66%{opacity:1}}
@keyframes eye-frame-mid-right{0%,31%,66%,100%{opacity:0}27%,62%{opacity:1}}
@keyframes eye-frame-right{0%,62%,100%{opacity:0}31%{opacity:1}}
.trip-portal{right:2%;top:13%;width:clamp(105px,14vw,190px);transform:rotate(4deg) scale(var(--hallucination-scale,1));transform-origin:center}.trip-portal img,.trip-depth-portal img{width:100%;filter:drop-shadow(5px 6px 0 var(--ink))}.trip-portal-nested{position:absolute;right:10%;top:18%;width:68%;transform:rotate(-9deg) scale(.72);transform-origin:center}.trip-portal-double{position:absolute;right:10%;top:18%;width:66%;transform:rotate(13deg) scale(.67);transform-origin:center;mix-blend-mode:multiply}
.trip-flying-washer{left:70%;top:62%;width:clamp(90px,13vw,180px);transform:rotate(-17deg) scale(var(--hallucination-scale,1));filter:drop-shadow(7px 7px 0 var(--ink))}.trip-washer-orbit{right:2%;bottom:7%;width:clamp(130px,18vw,250px);height:clamp(130px,18vw,250px);transform:rotate(-8deg) scale(var(--hallucination-scale,1))}.trip-washer-orbit>img:not(.trip-orbit-sock){position:absolute;width:56%;left:22%;top:21%;filter:drop-shadow(5px 5px 0 var(--ink))}.trip-orbit-sock{position:absolute;width:40%;height:60%;object-fit:contain;left:52%;top:32%;transform:rotate(28deg);filter:drop-shadow(4px 4px 0 var(--ink))}.trip-washer-orbit i{position:absolute;width:12px;height:12px;background:var(--orange);border:2px solid var(--ink);clip-path:polygon(12% 4%,88% 0,100% 72%,55% 100%,0 80%)}.trip-washer-orbit i:nth-child(3){left:1%;top:45%}.trip-washer-orbit i:nth-child(4){right:5%;top:8%}
.trip-paint-tunnel{inset:0}.trip-paint-tunnel b{position:absolute;left:50%;top:49%;width:var(--hallucination-tunnel-a,80px);height:var(--hallucination-tunnel-b,55px);border:7px solid var(--orange);box-shadow:10px 8px 0 var(--ink),-8px -4px 0 #69a5a0;transform:translate(-50%,-50%) rotate(7deg) scale(.45);clip-path:polygon(5% 3%,98% 0,100% 89%,86% 100%,1% 93%)}.trip-paint-tunnel b:nth-child(2){transform:translate(-50%,-50%) rotate(-8deg) scale(.9);border-color:#68a96c}.trip-paint-tunnel b:nth-child(3){transform:translate(-50%,-50%) rotate(4deg) scale(1.6);border-color:#ef7750}.trip-paint-tunnel b:nth-child(4){transform:translate(-50%,-50%) rotate(-13deg) scale(2.5);border-color:#7bb6b1}
.trip-depth-portal{left:50%;top:62%;width:min(34vw,430px);transform:translate(-50%,-50%) rotate(-3deg) scale(var(--hallucination-scale,1))}.trip-depth-portal>div{padding:12%;background:#222b20;clip-path:polygon(2% 5%,98% 0,94% 100%,5% 96%);box-shadow:12px 12px 0 var(--orange)}.trip-depth-portal>div>div{padding:12%;background:#df6b3f;clip-path:polygon(0 4%,100% 0,97% 97%,3% 100%)}.trip-depth-portal img{filter:hue-rotate(50deg) drop-shadow(4px 4px 0 #222b20)}
.trip-double-vision{inset:0;background-position:center top;background-size:100% auto;background-repeat:no-repeat;mix-blend-mode:screen;opacity:min(var(--apparition-opacity,0),.08);transform:translate(8px,3px);filter:sepia(.5) hue-rotate(115deg)}.trip-color-ghost{inset:0;background:rgba(226,65,80,.1);mix-blend-mode:screen;opacity:min(var(--apparition-opacity,0),.12);transform:translateX(var(--hallucination-offset,0px));box-shadow:inset 18vw 0 rgba(51,126,230,.06),inset -22vw 0 rgba(241,191,47,.06)}
.trip-cosmic-procession{right:5%;bottom:7%;width:min(52vw,650px);height:170px}.trip-cosmic-procession img{position:absolute;filter:drop-shadow(4px 5px 0 var(--ink))}.process-eye{width:72px;left:0;bottom:56px;transform:rotate(-16deg)}.process-washer{width:145px;left:23%;bottom:20px;transform:rotate(9deg)}.process-smoke{width:115px;height:145px;left:54%;bottom:12px;transform:rotate(-8deg)}.process-sock{width:75px;height:130px;object-fit:contain;right:3%;bottom:9px;transform:rotate(21deg)}
/* The late procession crosses the illustration, leaving the joint text clear. */
.trip-hallucination-layer:not(.trip-active){visibility:hidden;opacity:0;transition:none}
.trip-hallucination-layer.trip-reduced-motion{transition:none!important}
.trip-cosmic-procession{top:40%;bottom:auto}
@keyframes hallucination-orbital-laundry{0%,100%{transform:rotate(-8deg) translate(0,0)}50%{transform:rotate(18deg) translate(-20px,-16px)}}
.trip-active .trip-washer-orbit{animation:hallucination-orbital-laundry 14s ease-in-out infinite}
@keyframes hallucination-eye-peek{0%,100%{transform:rotate(-14deg) translate(0,0)}50%{transform:rotate(-8deg) translate(14px,-8px)}}@keyframes hallucination-door-slide{0%,100%{transform:rotate(4deg) translate(0,0) scale(var(--hallucination-scale,1))}50%{transform:rotate(1deg) translate(-12px,10px) scale(var(--hallucination-scale,1))}}@keyframes hallucination-washer-float{0%,100%{transform:rotate(-17deg) translate(0,0) scale(var(--hallucination-scale,1))}50%{transform:rotate(-7deg) translate(-22px,18px) scale(var(--hallucination-scale,1))}}@keyframes hallucination-recursive-breathe{0%,100%{transform:translate(-50%,-50%) rotate(-3deg) scale(var(--hallucination-scale,1))}50%{transform:translate(-50%,-50%) rotate(2deg) scale(1.04)}}@keyframes hallucination-procession{0%,100%{transform:translateX(0) rotate(-1deg)}50%{transform:translateX(-18px) rotate(2deg)}}
.trip-hallucination-layer .trip-ghost-eye,.trip-hallucination-layer .trip-portal,.trip-hallucination-layer .trip-flying-washer,.trip-hallucination-layer .trip-depth-portal,.trip-hallucination-layer .trip-cosmic-procession{animation-play-state:paused}.trip-active .trip-ghost-eye{animation:hallucination-eye-peek 6.8s ease-in-out infinite;animation-play-state:running}.trip-active .trip-portal{animation:hallucination-door-slide 9s ease-in-out infinite;animation-play-state:running}.trip-active .trip-flying-washer{animation:hallucination-washer-float 7.5s ease-in-out infinite;animation-play-state:running}.trip-active .trip-depth-portal{animation:hallucination-recursive-breathe 11s ease-in-out infinite;animation-play-state:running}.trip-active .trip-cosmic-procession{animation:hallucination-procession 8s ease-in-out infinite;animation-play-state:running}.trip-reduced-motion *,.trip-reduced-motion [data-trip-stage]{animation:none!important;transition:none!important}
@media(max-width:600px){.trip-portal{right:1%;top:12%;width:120px}.trip-portal-nested{right:10%;top:18%;width:68%}.trip-portal-double{right:10%;top:18%;width:66%}.trip-ghost-eye{left:1%;top:65%;width:95px}.trip-flying-washer{left:65%;top:64%;width:125px}.trip-washer-orbit{right:-22px;bottom:9%;width:170px;height:170px}.trip-depth-portal{width:70vw;top:66%}.trip-paint-tunnel b{border-width:4px}.trip-cosmic-procession{right:1%;bottom:9%;width:94vw;height:125px}.process-eye{width:54px}.process-washer{width:105px}.process-smoke{width:85px;height:105px}.process-sock{width:58px;height:98px}}@media(prefers-reduced-motion:reduce){.trip-hallucination-layer,.trip-hallucination-layer *{animation:none!important;transition:none!important}}

/* A quiet tint builds through puff six. Puff seven flips the cheap MLG
   switch: image layers cycle through saturated Paint colours slowly enough
   to stay legible, while fixed controls and the scrollbar remain untouched. */
@keyframes trip-color-cycle{0%,100%{filter:hue-rotate(var(--trip-color-hue)) saturate(var(--trip-color-saturation)) contrast(var(--trip-color-contrast))}50%{filter:hue-rotate(calc(var(--trip-color-hue) + 180deg)) saturate(calc(var(--trip-color-saturation) + var(--trip-mlg))) contrast(var(--trip-color-contrast))}}
body.tripping .hero-image,body.tripping .panel-art>img,body.tripping .portrait>img,body.tripping .dusty-inner img,body.tripping .trip-prop{filter:hue-rotate(var(--trip-color-hue)) saturate(var(--trip-color-saturation)) contrast(var(--trip-color-contrast))}
body[data-trip="7"] .hero-image,body[data-trip="7"] .panel-art>img,body[data-trip="7"] .portrait>img,body[data-trip="7"] .dusty-inner img,
body[data-trip="8"] .hero-image,body[data-trip="8"] .panel-art>img,body[data-trip="8"] .portrait>img,body[data-trip="8"] .dusty-inner img,
body[data-trip="9"] .hero-image,body[data-trip="9"] .panel-art>img,body[data-trip="9"] .portrait>img,body[data-trip="9"] .dusty-inner img,
body[data-trip="10"] .hero-image,body[data-trip="10"] .panel-art>img,body[data-trip="10"] .portrait>img,body[data-trip="10"] .dusty-inner img{animation:trip-color-cycle var(--trip-color-speed) ease-in-out infinite}
/* One continuous paper wash: section-sized fills expose hard edges while scrolling. */
body.tripping{--trip-paper-echo:color-mix(in srgb,var(--orange) calc(var(--trip-mlg) * 22%),transparent);background-image:linear-gradient(var(--trip-paper-echo),var(--trip-paper-echo))}
/* The body already carries paper texture. Do not tint a second copy just in the comic. */
body.tripping .comic-section:before{content:none}
body.tripping .trip-hallucination-layer{filter:hue-rotate(var(--trip-color-hue)) saturate(var(--trip-color-saturation))}
body.tripping .trip-hallucination-layer.trip-reduced-motion,body.tripping .trip-hallucination-layer.trip-reduced-motion img{animation:none!important}

/* Each late stage gets its own cheap printed colour wash. The overlay lives
   in the existing non-interactive trip layer, so it cannot trap clicks or
   alter fixed-position geometry. */
body[data-trip="7"] .trip-world:before{background:linear-gradient(115deg,#b7ff9b,#5ed7d5 52%,#ec74c6);opacity:.13}
body[data-trip="8"] .trip-world:before{background:linear-gradient(115deg,#a6ff73,#43c9ff 48%,#ff64c7);opacity:.18}
body[data-trip="9"] .trip-world:before{background:linear-gradient(115deg,#77ff62,#2ce6e9 45%,#ff3eaf);opacity:.24}
body[data-trip="10"] .trip-world:before{background:linear-gradient(115deg,#54ff48,#00d9ff 42%,#ff238d);opacity:.31}
body[data-trip="7"] .comic-section,body[data-trip="7"] .locals-section{border-color:#63c9ba}
body[data-trip="8"] .comic-section,body[data-trip="8"] .locals-section{border-color:#47c9d4}
body[data-trip="9"] .comic-section,body[data-trip="9"] .locals-section{border-color:#5bdc8b}
body[data-trip="10"] .comic-section,body[data-trip="10"] .locals-section{border-color:#e752a7}
body[data-trip="7"] .comic-heading-row h2,body[data-trip="7"] .locals-heading h2,body[data-trip="7"] .dusty-copy h2,
body[data-trip="8"] .comic-heading-row h2,body[data-trip="8"] .locals-heading h2,body[data-trip="8"] .dusty-copy h2,
body[data-trip="9"] .comic-heading-row h2,body[data-trip="9"] .locals-heading h2,body[data-trip="9"] .dusty-copy h2,
body[data-trip="10"] .comic-heading-row h2,body[data-trip="10"] .locals-heading h2,body[data-trip="10"] .dusty-copy h2{ text-shadow:calc(var(--trip-mlg) * 3px) 1px 0 #00e5ff,calc(var(--trip-mlg) * -3px) -1px 0 #ff238d }
@media(prefers-reduced-motion:reduce){body.tripping .hero-image,body.tripping .panel-art>img,body.tripping .portrait>img,body.tripping .dusty-inner img{animation:none!important}}

.trip-reduced-motion .trip-smoke-frame,.trip-world.trip-reduced-motion .trip-smoke-frame{animation:none!important}
@media(prefers-reduced-motion:reduce){.trip-smoke-frame{animation:none!important}}

/* Hallucination props float on a spring while held and drift after a throw.
   Keep the drag offset in the independent `translate` property so each
   prop's deliberately bad Paint rotation and its existing animation survive. */
[data-trip-drag]{
  pointer-events:none;
  cursor:grab;
  touch-action:none;
  user-select:none;
  -webkit-user-drag:none;
}
[data-trip-drag] img{
  pointer-events:none;
  user-select:none;
  -webkit-user-drag:none;
}
.trip-cosmic-procession img[data-trip-drag][data-trip-draggable="true"]{
  pointer-events:auto;
}
.trip-active [data-trip-drag][data-trip-draggable="true"],
body.tripping .trip-world [data-trip-drag][data-trip-draggable="true"],
body.tripping .trip-hallucination-layer [data-trip-drag][data-trip-draggable="true"]{
  pointer-events:auto;
}
[data-trip-drag].is-trip-dragging{
  cursor:grabbing;
  animation-play-state:paused!important;
  translate:var(--trip-drag-x,0px) var(--trip-drag-y,0px)!important;
  rotate:calc(var(--trip-drag-base-angle,0deg) + var(--trip-drag-angle,0deg))!important;
}
[data-trip-drag][data-trip-moved="true"]{
  cursor:grab;
  animation-play-state:paused!important;
  translate:var(--trip-drag-x,0px) var(--trip-drag-y,0px)!important;
  rotate:calc(var(--trip-drag-base-angle,0deg) + var(--trip-drag-angle,0deg))!important;
}
[data-trip-drag]:focus-visible{
  outline:3px dashed var(--orange);
  outline-offset:5px;
}
.trip-hallucination-layer:has(.trip-cosmic-procession [data-trip-drag].is-trip-dragging) .trip-cosmic-procession,
.trip-hallucination-layer:has(.trip-cosmic-procession [data-trip-drag][data-trip-moved="true"]) .trip-cosmic-procession{
  animation-play-state:paused!important;
}
html.loader-active [data-trip-drag],
html.reader-open [data-trip-drag],
html.smoke-pending [data-trip-drag],
body.loader-active [data-trip-drag],
body.reader-open [data-trip-drag],
body.smoke-pending [data-trip-drag]{
  pointer-events:none!important;
}

/* The trip layer may cross the invitation, but only the joint and reset
   controls should claim pointer events there. */
.smoke-invitation{
  z-index:31;
  pointer-events:none;
}
.smoke-invitation .joint-control{
  pointer-events:auto;
}
#fresh-air{
  position:relative;
  z-index:31;
}

/* Generated hallucination cels use the same one-pose-at-a-time rhythm as the
   eye.  The original first raster remains visible until every new cel is
   decoded, so a missing generated frame never leaves a blank object. */
.trip-cel-art{position:relative;display:block;isolation:isolate;aspect-ratio:1;filter:drop-shadow(5px 5px 0 var(--ink))}
.trip-cel-art.trip-sock-art{aspect-ratio:2 / 3}
.trip-cel-art>.trip-cel-frame{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;opacity:0;animation-duration:5.4s;animation-timing-function:steps(1,end);animation-iteration-count:infinite;animation-play-state:paused;pointer-events:none;filter:none}
.trip-cel-art>.trip-cel-frame-1{opacity:1}
.trip-cel-ready>.trip-cel-frame-1{animation-name:trip-cel-frame-1}
.trip-cel-ready>.trip-cel-frame-2{animation-name:trip-cel-frame-2}
.trip-cel-ready>.trip-cel-frame-3{animation-name:trip-cel-frame-3}
.trip-cel-ready>.trip-cel-frame-4{animation-name:trip-cel-frame-4}
.trip-cel-ready>.trip-cel-frame-5{animation-name:trip-cel-frame-5}
 .trip-active .trip-cel-ready>.trip-cel-frame,body.tripping .trip-world .trip-cel-ready>.trip-cel-frame{animation-play-state:running}
@keyframes trip-cel-frame-1{0%,100%{opacity:1}20%{opacity:0}80%{opacity:1}}
@keyframes trip-cel-frame-2{0%,100%{opacity:0}20%{opacity:1}40%{opacity:0}}
@keyframes trip-cel-frame-3{0%,100%{opacity:0}40%{opacity:1}43%{opacity:0}}
@keyframes trip-cel-frame-4{0%,100%{opacity:0}43%{opacity:1}65%{opacity:0}}
@keyframes trip-cel-frame-5{0%,100%{opacity:0}65%{opacity:1}80%{opacity:0}}
.trip-portal>.trip-cel-art,.trip-portal-nested>.trip-cel-art,.trip-portal-double>.trip-cel-art{width:100%;height:auto;aspect-ratio:3 / 4}
.trip-flying-washer>.trip-cel-art{width:100%;height:auto;aspect-ratio:4 / 3}
.trip-washer-orbit>.trip-cel-art:not(.trip-orbit-sock){position:absolute;width:56%;height:auto;aspect-ratio:4 / 3;left:22%;top:21%}
.trip-orbit-sock{position:absolute;width:40%;height:60%;left:52%;top:32%;transform:rotate(28deg);filter:drop-shadow(4px 4px 0 var(--ink))}
.trip-depth-portal .trip-cel-art{width:100%;height:100%}
.process-washer,.process-sock{position:absolute}
.process-washer>.trip-cel-art{width:100%;height:100%}
.process-sock>.trip-cel-art{width:100%;height:100%}
.trip-cosmic-procession{inset:0!important;width:auto!important;height:auto!important;pointer-events:none}
.trip-active .trip-cosmic-procession{animation:none!important}
.trip-cosmic-procession>[data-trip-drag]{position:absolute}
.trip-cosmic-procession .process-eye,.trip-cosmic-procession .process-washer,.trip-cosmic-procession .process-smoke,.trip-cosmic-procession .process-sock{bottom:auto;right:auto}
.trip-prop.trip-sock{aspect-ratio:2 / 3;height:auto}
.trip-prop.trip-sock>.trip-cel-art{width:100%;height:100%}
@media(prefers-reduced-motion:reduce){.trip-cel-art>.trip-cel-frame{animation:none!important}}
.trip-page-hidden .trip-cel-art>.trip-cel-frame{animation-play-state:paused!important}

/* Painted cels provide the idle movement. A stable outer body lets placement
   and spring physics share the same measured viewport geometry. */
.trip-world .trip-random-body{animation:none!important;--hallucination-scale:1;will-change:auto}
.trip-random-body.sock-one{transform:rotate(-9deg)}
.trip-random-body.sock-two{transform:rotate(13deg)}
.trip-cosmic-procession{animation:none!important;transform:none!important}
.trip-cel-art.trip-portal-art{aspect-ratio:3 / 4}
.trip-cel-art.trip-washer-art{aspect-ratio:4 / 3}
.trip-depth-portal .trip-cel-art{height:auto;aspect-ratio:3 / 4}
.trip-cosmic-procession>.process-washer{height:auto;aspect-ratio:4 / 3}
.trip-cosmic-procession>.process-sock{height:auto;aspect-ratio:2 / 3}
.trip-eye-art>.trip-eye-frame,.trip-smoke-art>.trip-smoke-frame,.trip-cel-art>.trip-cel-frame{animation-delay:var(--trip-cel-delay,0s)}
.trip-world:not(.trip-running) .trip-eye-frame,
.trip-world:not(.trip-running) .trip-smoke-frame,
.trip-world:not(.trip-running) .trip-cel-frame,
.trip-world.trip-page-hidden .trip-eye-frame,
.trip-world.trip-page-hidden .trip-smoke-frame,
.trip-world.trip-page-hidden .trip-cel-frame{animation-play-state:paused!important}
