.oart-lava {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    isolation: isolate;
    background: var(--oart-lava-background-colour);
}

/* Add the oart-lava-fill class (Advanced > CSS Classes) to make a field cover
   the layer it sits in, instead of using its Minimum Height. The layer is
   absolutely positioned, so inset:0 gives a definite height for the percentage
   heights below to resolve against. Fields without the class are untouched. */
.elementor-widget-oart-lava-gradient.oart-lava-fill {
    position: absolute;
    inset: 0;
}

.elementor-widget-oart-lava-gradient.oart-lava-fill > .elementor-widget-container {
    height: 100%;
}

/* Hold the blobs still inside the Elementor editor. The fields still render so
   they can be seen and styled, but a canvas full of looping blobs pins the CPU
   and makes editing sluggish. The front end is unaffected. */
body.elementor-editor-active .oart-lava__blob {
    animation: none !important;
}

.oart-lava__field {
    position: absolute;
    inset: 0;
    transform: scale(1.16);
}

/* Per-shape blur sits on a wrapper, not on the blob itself.
   `filter` is applied BEFORE clip-path and mask, so blurring the blob direct
   works for the round shapes but gets clipped straight back off the geometric
   and masked ones: measured, a blurred triangle came back with hard edges.
   A parent filter runs on the child's finished output, so it blurs every shape
   the same. The wrapper is absolutely positioned to the field's own box, so the
   blobs' percentage offsets still resolve against exactly what they did before. */
.oart-lava__blur {
    position: absolute;
    inset: 0;
}

.oart-lava__blur--one { filter: blur(var(--oart-lava-blur1, 0px)); }
.oart-lava__blur--two { filter: blur(var(--oart-lava-blur2, 0px)); }
.oart-lava__blur--three { filter: blur(var(--oart-lava-blur3, 0px)); }
.oart-lava__blur--four { filter: blur(var(--oart-lava-blur4, 0px)); }
.oart-lava__blur--five { filter: blur(var(--oart-lava-blur5, 0px)); }

/* Each blob's own width lives in --oart-lava-wN so the Individual Shapes
   controls can set it, and Shape Size scales all five together.
   --oart-lava-stretch is the shape's built-in width:height bias (an oval is
   wider than tall before anyone touches a slider); Shape Length multiplies it. */
.oart-lava__blob {
    position: absolute;
    display: block;
    aspect-ratio: calc(var(--oart-lava-stretch, 1) * var(--oart-lava-length, 100) / 100);
    border-radius: 44% 56% 58% 42% / 52% 42% 58% 48%;
    background: var(--oart-lava-fill);
    clip-path: var(--oart-lava-clip, none);
    will-change: transform, border-radius;
}

/* Position is a nudge from each blob's built-in spot, not an absolute
   coordinate, so 0 is the composition the widget has always had and nothing
   moves on pages that predate the controls. Two of the blobs hang off the
   right and bottom edges; their offsets are subtracted so that a positive X
   is always rightwards and a positive Y always downwards, whichever edge the
   blob happens to be anchored to. */
.oart-lava__blob--one {
    top: calc(-8% + var(--oart-lava-y1, 0%));
    left: calc(-4% + var(--oart-lava-x1, 0%));
    width: calc(var(--oart-lava-w1, 48%) * var(--oart-lava-size, 1));
    --oart-lava-fill: var(--oart-lava-colour-1);
}

.oart-lava__blob--two {
    top: calc(5% + var(--oart-lava-y2, 0%));
    right: calc(-2% - var(--oart-lava-x2, 0%));
    width: calc(var(--oart-lava-w2, 42%) * var(--oart-lava-size, 1));
    --oart-lava-fill: var(--oart-lava-colour-2);
}

.oart-lava__blob--three {
    right: calc(24% - var(--oart-lava-x3, 0%));
    bottom: calc(-18% - var(--oart-lava-y3, 0%));
    width: calc(var(--oart-lava-w3, 39%) * var(--oart-lava-size, 1));
    --oart-lava-fill: var(--oart-lava-colour-3);
}

.oart-lava__blob--four {
    bottom: calc(-4% - var(--oart-lava-y4, 0%));
    left: calc(12% + var(--oart-lava-x4, 0%));
    width: calc(var(--oart-lava-w4, 36%) * var(--oart-lava-size, 1));
    --oart-lava-fill: var(--oart-lava-colour-4);
}

.oart-lava__blob--five {
    top: calc(26% + var(--oart-lava-y5, 0%));
    left: calc(36% + var(--oart-lava-x5, 0%));
    width: calc(var(--oart-lava-w5, 31%) * var(--oart-lava-size, 1));
    --oart-lava-fill: var(--oart-lava-colour-5);
}

/* Shape catalogue. PHP resolves the main shape and any per-blob override into
   one class per blob, so there is a single rule per shape and no specificity
   fight between a widget-wide setting and an individual one.
   Round-family shapes use border-radius; the geometry uses clip-path. Only
   --blob keeps the morphing outline, so a triangle stays a triangle. */
.oart-lava__blob--circle {
    border-radius: 50%;
}

.oart-lava__blob--oval {
    border-radius: 50%;
    --oart-lava-stretch: 1.55;
}

.oart-lava__blob--pill {
    border-radius: 9999px;
    --oart-lava-stretch: 2.6;
}

.oart-lava__blob--arch {
    border-radius: 50% 50% 6% 6% / 88% 88% 6% 6%;
}

.oart-lava__blob--leaf {
    border-radius: 78% 6% 78% 6%;
}

.oart-lava__blob--ring {
    border-radius: 50%;
    background: radial-gradient(closest-side, transparent 0 54%, var(--oart-lava-fill) 56% 100%);
}

.oart-lava__blob--triangle {
    border-radius: 0;
    --oart-lava-clip: polygon(50% 0%, 100% 100%, 0% 100%);
}

.oart-lava__blob--diamond {
    border-radius: 0;
    --oart-lava-clip: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

.oart-lava__blob--cross {
    border-radius: 0;
    --oart-lava-clip: polygon(36% 0%, 64% 0%, 64% 36%, 100% 36%, 100% 64%, 64% 64%, 64% 100%, 36% 100%, 36% 64%, 0% 64%, 0% 36%, 36% 36%);
}

.oart-lava__blob--star {
    border-radius: 0;
    --oart-lava-clip: polygon(50% 0%, 57.7% 31.5%, 85.4% 14.6%, 68.5% 42.3%, 100% 50%, 68.5% 57.7%, 85.4% 85.4%, 57.7% 68.5%, 50% 100%, 42.3% 68.5%, 14.6% 85.4%, 31.5% 57.7%, 0% 50%, 31.5% 42.3%, 14.6% 14.6%, 42.3% 31.5%);
}

.oart-lava__blob--amoeba {
    border-radius: 0;
    --oart-lava-clip: polygon(50% 5.7%, 57% 5.9%, 63.4% 8.7%, 69.1% 12.6%, 74.2% 16.6%, 79.3% 20.7%, 83.7% 25.5%, 86.6% 31.4%, 87.2% 37.9%, 86% 44.3%, 84.2% 50%, 83.4% 55.3%, 84% 61.1%, 85.1% 67.9%, 84.9% 75.3%, 81.8% 81.8%, 75.9% 85.6%, 68.4% 86.1%, 61.1% 84.3%, 55.1% 82.1%, 50% 81.4%, 44.9% 82.4%, 38.9% 84.2%, 32.2% 84.9%, 25.7% 83.4%, 20.2% 79.8%, 15.7% 74.9%, 11.9% 69.4%, 8.2% 63.6%, 5.1% 57.1%, 3.9% 50%, 5.9% 43%, 11.1% 37.4%, 18.4% 33.9%, 25.4% 32.2%, 30.6% 30.6%, 33.6% 27.4%, 35.6% 21.8%, 38.6% 15%, 43.5% 8.9%);
}

.oart-lava__blob--squiggle {
    border-radius: 0;
    --oart-lava-stretch: 2.2;
    --oart-lava-clip: polygon(0% 36%, 5% 50.1%, 10% 58.8%, 15% 58.8%, 20% 50.1%, 25% 36%, 30% 21.9%, 35% 13.2%, 40% 13.2%, 45% 21.9%, 50% 36%, 55% 50.1%, 60% 58.8%, 65% 58.8%, 70% 50.1%, 75% 36%, 80% 21.9%, 85% 13.2%, 90% 13.2%, 95% 21.9%, 100% 36%, 100% 64%, 95% 49.9%, 90% 41.2%, 85% 41.2%, 80% 49.9%, 75% 64%, 70% 78.1%, 65% 86.8%, 60% 86.8%, 55% 78.1%, 50% 64%, 45% 49.9%, 40% 41.2%, 35% 41.2%, 30% 49.9%, 25% 64%, 20% 78.1%, 15% 86.8%, 10% 86.8%, 5% 78.1%, 0% 64%);
}

.oart-lava__blob--scurve {
    border-radius: 0;
    --oart-lava-stretch: 1.09;
    --oart-lava-clip: polygon(13.4% 98.5%, 17.3% 98.4%, 21.1% 98%, 24.7% 97.4%, 28.1% 96.5%, 31.4% 95.3%, 34.5% 93.9%, 37.4% 92.2%, 40.2% 90.4%, 42.7% 88.3%, 45% 86.1%, 47.2% 83.7%, 49.1% 81.2%, 50.8% 78.7%, 52.4% 76.1%, 53.8% 73.5%, 55% 70.9%, 56.2% 68.4%, 57.2% 65.8%, 58.2% 63.2%, 59.1% 60.7%, 60% 58.3%, 60.8% 55.9%, 61.6% 53.5%, 62.3% 51.2%, 63.1% 49%, 63.8% 47%, 64.6% 45%, 65.4% 43.1%, 66.2% 41.3%, 67% 39.7%, 67.8% 38.2%, 68.6% 36.8%, 69.4% 35.6%, 70.3% 34.5%, 71.2% 33.5%, 72.1% 32.6%, 73.1% 31.8%, 74.2% 31%, 75.4% 30.4%, 76.7% 29.8%, 78.2% 29.2%, 79.9% 28.8%, 81.9% 28.4%, 84.1% 28.2%, 86.6% 28.1%, 89.7% 27.7%, 92.5% 26.4%, 95% 24.2%, 96.9% 21.5%, 98.1% 18.3%, 98.5% 14.8%, 98.1% 11.4%, 96.9% 8.2%, 95% 5.4%, 92.5% 3.3%, 89.7% 2%, 86.6% 1.5%, 82.7% 1.6%, 78.9% 2%, 75.3% 2.6%, 71.9% 3.5%, 68.6% 4.7%, 65.5% 6.1%, 62.6% 7.8%, 59.8% 9.6%, 57.3% 11.7%, 55% 13.9%, 52.8% 16.3%, 50.9% 18.8%, 49.2% 21.3%, 47.6% 23.9%, 46.2% 26.5%, 45% 29.1%, 43.8% 31.6%, 42.8% 34.2%, 41.8% 36.8%, 40.9% 39.3%, 40% 41.7%, 39.2% 44.1%, 38.4% 46.5%, 37.7% 48.8%, 36.9% 51%, 36.2% 53%, 35.4% 55%, 34.6% 56.9%, 33.8% 58.7%, 33% 60.3%, 32.2% 61.8%, 31.4% 63.2%, 30.6% 64.4%, 29.7% 65.5%, 28.8% 66.5%, 27.9% 67.4%, 26.9% 68.2%, 25.8% 69%, 24.6% 69.6%, 23.3% 70.2%, 21.8% 70.8%, 20.1% 71.2%, 18.1% 71.6%, 15.9% 71.8%, 13.4% 71.9%, 10.3% 72.3%, 7.5% 73.6%, 5% 75.8%, 3.1% 78.5%, 1.9% 81.7%, 1.5% 85.2%, 1.9% 88.6%, 3.1% 91.8%, 5% 94.6%, 7.5% 96.7%, 10.3% 98%);
}

/* The OART wordmark. Every other shape is a border-radius or a clip-path, but
   this one has counters in the O, A and R, and a polygon cannot hold a hole.
   A mask can, so the artwork masks the blob's own background and the colour
   stays a picker. It cannot morph for the same reason: there is no equivalent
   80-point outline, so shape_paths() has no entry and the widget quietly
   leaves it static. */
.oart-lava__blob--oartlogo {
    border-radius: 0;
    --oart-lava-stretch: 2.7734;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 440.64 158.88'%3E%3Cpath d='M440.64,24.89v-10.28c0-5.63-4.57-10.2-10.2-10.2h-195.42c-5.63,0-10.2,4.57-10.2,10.2v55.18l-24.21-59.05c-1.57-3.82-5.3-6.33-9.44-6.33h-23.84c-4.14,0-7.87,2.51-9.42,6.33l-10.46,25.49C134.42,14.41,110.78,0,79.44,0,30.23,0,0,35.53,0,79.44s28.87,78.07,76.61,79.4c.94.04,1.88.05,2.83.05h45.65c3.86,0,7.4-2.18,9.12-5.64l.71-1.43c8.82-13.91,25.16-20.97,44.35-20.97s35.53,7.06,44.35,20.97l.72,1.43c1.73,3.45,5.25,5.64,9.11,5.64h12.71s.03,0,.05,0h3.51c5.63,0,10.2-4.57,10.2-10.2v-31.02c0-5.63,4.57-10.2,10.2-10.2h8.56c25.47,0,41.68,10.37,44.22,42.14.42,5.26,4.88,9.28,10.15,9.28h11.05c5.89,0,10.53-4.98,10.18-10.87-1.58-26.63-9.2-42.35-21.32-51.14,11.92-9.05,18.32-23.39,18.32-40.82,0-7.62-1.07-14.67-3.26-20.96h12.96v113.6c0,5.63,4.57,10.2,10.2,10.2h14.69c5.63,0,10.2-4.57,10.2-10.2V35.09h34.38c5.63,0,10.2-4.57,10.2-10.2ZM34.87,79.44c0-26.92,17.65-48.76,44.57-48.76,10.22,0,19.09,3.15,26.17,8.51l19.63-10.34-8.08,23.61c4.42,7.73,6.86,17,6.86,26.98,0,26.93-17.43,48.78-44.58,48.78s-44.57-21.85-44.57-48.78ZM178.82,99.96c-8.6,0-16.1,1.55-22.51,4.63l22.95-58.03,23.18,58.03c-6.85-3.08-14.78-4.63-23.62-4.63ZM291.91,80.1h-21.8c-5.63,0-10.2-4.57-10.2-10.2v-34.82h32c16.77,0,24.71,8.16,24.71,21.85s-8.61,23.17-24.71,23.17Z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 440.64 158.88'%3E%3Cpath d='M440.64,24.89v-10.28c0-5.63-4.57-10.2-10.2-10.2h-195.42c-5.63,0-10.2,4.57-10.2,10.2v55.18l-24.21-59.05c-1.57-3.82-5.3-6.33-9.44-6.33h-23.84c-4.14,0-7.87,2.51-9.42,6.33l-10.46,25.49C134.42,14.41,110.78,0,79.44,0,30.23,0,0,35.53,0,79.44s28.87,78.07,76.61,79.4c.94.04,1.88.05,2.83.05h45.65c3.86,0,7.4-2.18,9.12-5.64l.71-1.43c8.82-13.91,25.16-20.97,44.35-20.97s35.53,7.06,44.35,20.97l.72,1.43c1.73,3.45,5.25,5.64,9.11,5.64h12.71s.03,0,.05,0h3.51c5.63,0,10.2-4.57,10.2-10.2v-31.02c0-5.63,4.57-10.2,10.2-10.2h8.56c25.47,0,41.68,10.37,44.22,42.14.42,5.26,4.88,9.28,10.15,9.28h11.05c5.89,0,10.53-4.98,10.18-10.87-1.58-26.63-9.2-42.35-21.32-51.14,11.92-9.05,18.32-23.39,18.32-40.82,0-7.62-1.07-14.67-3.26-20.96h12.96v113.6c0,5.63,4.57,10.2,10.2,10.2h14.69c5.63,0,10.2-4.57,10.2-10.2V35.09h34.38c5.63,0,10.2-4.57,10.2-10.2ZM34.87,79.44c0-26.92,17.65-48.76,44.57-48.76,10.22,0,19.09,3.15,26.17,8.51l19.63-10.34-8.08,23.61c4.42,7.73,6.86,17,6.86,26.98,0,26.93-17.43,48.78-44.58,48.78s-44.57-21.85-44.57-48.78ZM178.82,99.96c-8.6,0-16.1,1.55-22.51,4.63l22.95-58.03,23.18,58.03c-6.85-3.08-14.78-4.63-23.62-4.63ZM291.91,80.1h-21.8c-5.63,0-10.2-4.57-10.2-10.2v-34.82h32c16.77,0,24.71,8.16,24.71,21.85s-8.61,23.17-24.71,23.17Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.oart-lava__blob--zigzag {
    border-radius: 0;
    --oart-lava-stretch: 2.2;
    --oart-lava-clip: polygon(0% 63%, 4.2% 50.5%, 8.3% 38%, 12.5% 25.5%, 16.7% 13%, 20.8% 25.5%, 25% 38%, 29.2% 50.5%, 33.3% 63%, 37.5% 50.5%, 41.7% 38%, 45.8% 25.5%, 50% 13%, 54.2% 25.5%, 58.3% 38%, 62.5% 50.5%, 66.7% 63%, 70.8% 50.5%, 75% 38%, 79.2% 25.5%, 83.3% 13%, 87.5% 25.5%, 91.7% 38%, 95.8% 50.5%, 100% 63%, 100% 87%, 95.8% 74.5%, 91.7% 62%, 87.5% 49.5%, 83.3% 37%, 79.2% 49.5%, 75% 62%, 70.8% 74.5%, 66.7% 87%, 62.5% 74.5%, 58.3% 62%, 54.2% 49.5%, 50% 37%, 45.8% 49.5%, 41.7% 62%, 37.5% 74.5%, 33.3% 87%, 29.2% 74.5%, 25% 62%, 20.8% 49.5%, 16.7% 37%, 12.5% 49.5%, 8.3% 62%, 4.2% 74.5%, 0% 87%);
}

/* A blob that is turning into another shape carries no shape class at all: both
   ends of the shift come from the 80-point table in lava-shape-paths.php and are
   written inline, so the base outline here has to get out of the way. The widget
   emits the keyframes itself, since the pair of shapes is per instance. */
.oart-lava__blob--shifting {
    border-radius: 0;
    background: var(--oart-lava-fill);
}

/* Movement and outline-morph are separate animations so a fixed shape can take
   the drift without the border-radius morph rewriting its outline. Organic
   blobs get both, at the same duration and delay, so they look exactly as
   before. */
.oart-lava--animated .oart-lava__blob--one {
    animation: oart-lava-one var(--oart-lava-speed) ease-in-out infinite alternate;
}

.oart-lava--animated .oart-lava__blob--two {
    animation: oart-lava-two calc(var(--oart-lava-speed) * 1.18) ease-in-out calc(var(--oart-lava-speed) * -.36) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--three {
    animation: oart-lava-three calc(var(--oart-lava-speed) * .86) ease-in-out calc(var(--oart-lava-speed) * -.54) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--four {
    animation: oart-lava-four calc(var(--oart-lava-speed) * 1.32) ease-in-out calc(var(--oart-lava-speed) * -.18) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--five {
    animation: oart-lava-five calc(var(--oart-lava-speed) * 1.06) ease-in-out calc(var(--oart-lava-speed) * -.72) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--organic.oart-lava__blob--one {
    animation:
        oart-lava-one var(--oart-lava-speed) ease-in-out infinite alternate,
        oart-lava-morph-one var(--oart-lava-speed) ease-in-out infinite alternate;
}

.oart-lava--animated .oart-lava__blob--organic.oart-lava__blob--two {
    animation:
        oart-lava-two calc(var(--oart-lava-speed) * 1.18) ease-in-out calc(var(--oart-lava-speed) * -.36) infinite alternate,
        oart-lava-morph-two calc(var(--oart-lava-speed) * 1.18) ease-in-out calc(var(--oart-lava-speed) * -.36) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--organic.oart-lava__blob--three {
    animation:
        oart-lava-three calc(var(--oart-lava-speed) * .86) ease-in-out calc(var(--oart-lava-speed) * -.54) infinite alternate,
        oart-lava-morph-three calc(var(--oart-lava-speed) * .86) ease-in-out calc(var(--oart-lava-speed) * -.54) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--organic.oart-lava__blob--four {
    animation:
        oart-lava-four calc(var(--oart-lava-speed) * 1.32) ease-in-out calc(var(--oart-lava-speed) * -.18) infinite alternate,
        oart-lava-morph-four calc(var(--oart-lava-speed) * 1.32) ease-in-out calc(var(--oart-lava-speed) * -.18) infinite alternate;
}

.oart-lava--animated .oart-lava__blob--organic.oart-lava__blob--five {
    animation:
        oart-lava-five calc(var(--oart-lava-speed) * 1.06) ease-in-out calc(var(--oart-lava-speed) * -.72) infinite alternate,
        oart-lava-morph-five calc(var(--oart-lava-speed) * 1.06) ease-in-out calc(var(--oart-lava-speed) * -.72) infinite alternate;
}

@keyframes oart-lava-one {
    0% { transform: translate3d(calc(var(--oart-lava-movement) * -.18), 0, 0) scale(.78) rotate(0); }
    48% { transform: translate3d(var(--oart-lava-movement), calc(var(--oart-lava-movement) * .55), 0) scale(1.2) rotate(42deg); }
    100% { transform: translate3d(calc(var(--oart-lava-movement) * .38), var(--oart-lava-movement), 0) scale(.9) rotate(86deg); }
}

@keyframes oart-lava-two {
    0% { transform: translate3d(0, calc(var(--oart-lava-movement) * .72), 0) scale(1.12) rotate(0); }
    50% { transform: translate3d(calc(var(--oart-lava-movement) * -1), calc(var(--oart-lava-movement) * .12), 0) scale(.82) rotate(-48deg); }
    100% { transform: translate3d(calc(var(--oart-lava-movement) * -.35), calc(var(--oart-lava-movement) * -.22), 0) scale(1.18) rotate(-92deg); }
}

@keyframes oart-lava-three {
    0% { transform: translate3d(calc(var(--oart-lava-movement) * .34), 0, 0) scale(.86) rotate(0); }
    51% { transform: translate3d(calc(var(--oart-lava-movement) * -.74), calc(var(--oart-lava-movement) * -.88), 0) scale(1.24) rotate(52deg); }
    100% { transform: translate3d(calc(var(--oart-lava-movement) * .42), calc(var(--oart-lava-movement) * -1.12), 0) scale(.94) rotate(96deg); }
}

@keyframes oart-lava-four {
    0% { transform: translate3d(calc(var(--oart-lava-movement) * -.2), calc(var(--oart-lava-movement) * -.1), 0) scale(1.14) rotate(0); }
    47% { transform: translate3d(calc(var(--oart-lava-movement) * 1.12), calc(var(--oart-lava-movement) * -.76), 0) scale(.8) rotate(-43deg); }
    100% { transform: translate3d(calc(var(--oart-lava-movement) * .46), calc(var(--oart-lava-movement) * -1.28), 0) scale(1.1) rotate(-84deg); }
}

@keyframes oart-lava-five {
    0% { transform: translate3d(0, calc(var(--oart-lava-movement) * -.42), 0) scale(.72) rotate(0); }
    49% { transform: translate3d(calc(var(--oart-lava-movement) * .64), calc(var(--oart-lava-movement) * .48), 0) scale(1.28) rotate(62deg); }
    100% { transform: translate3d(calc(var(--oart-lava-movement) * -.72), calc(var(--oart-lava-movement) * .82), 0) scale(.92) rotate(118deg); }
}

@keyframes oart-lava-morph-one {
    0% { border-radius: 44% 56% 58% 42% / 52% 42% 58% 48%; }
    48% { border-radius: 60% 40% 34% 66% / 39% 62% 38% 61%; }
    100% { border-radius: 36% 64% 61% 39% / 63% 36% 64% 37%; }
}

@keyframes oart-lava-morph-two {
    0% { border-radius: 59% 41% 48% 52% / 38% 56% 44% 62%; }
    50% { border-radius: 34% 66% 62% 38% / 61% 35% 65% 39%; }
    100% { border-radius: 62% 38% 41% 59% / 45% 66% 34% 55%; }
}

@keyframes oart-lava-morph-three {
    0% { border-radius: 42% 58% 37% 63% / 56% 41% 59% 44%; }
    51% { border-radius: 64% 36% 55% 45% / 35% 61% 39% 65%; }
    100% { border-radius: 37% 63% 44% 56% / 66% 42% 58% 34%; }
}

@keyframes oart-lava-morph-four {
    0% { border-radius: 56% 44% 66% 34% / 41% 58% 42% 59%; }
    47% { border-radius: 38% 62% 45% 55% / 64% 37% 63% 36%; }
    100% { border-radius: 65% 35% 58% 42% / 36% 63% 37% 64%; }
}

@keyframes oart-lava-morph-five {
    0% { border-radius: 63% 37% 46% 54% / 54% 38% 62% 46%; }
    49% { border-radius: 37% 63% 57% 43% / 42% 65% 35% 58%; }
    100% { border-radius: 58% 42% 35% 65% / 61% 44% 56% 39%; }
}

/* ===================================================================
   Interactive timeline

   Colour: each step takes one colour from the cycle, written per item in
   PHP as --oart-tl-c. The number, the dot and the speech bubble all read
   it, so one slot drives the whole step. Every one of them still has its
   own control; Elementor's selector is more specific than the base rule
   here, so a control with a value overrides the cycle and an empty one
   leaves the cycle alone.

   Shape: the bubble is an ellipse plus a tail. border-radius: 50% is the
   artwork's body exactly, at any width and height, so only the tail is
   drawn. The tail's base is buried at the bubble's CENTRE and its apex
   is the dot, both derived from the same angle and length — so the two
   cannot drift apart whatever the bubble is resized to. Same lesson as
   the chat: never let one part of a shape be measured off something the
   other part is not.
   =================================================================== */

.oart-timeline {
    /* The colour cycle's slots. Each one's Elementor control writes the same
       variable through its 'selectors', at a higher specificity, so these are
       only the resting values: they keep the widget correct before Elementor
       has generated its CSS, and they mirror the control defaults exactly. */
    --oart-tl-c1: #FFA63A;
    --oart-tl-c2: #DF31EB;
    --oart-tl-c3: #FF76BC;
    --oart-tl-c4: #9B5DF5;
    --oart-tl-c5: #FF6A63;

    --oart-timeline-label-height: 120px;
    --oart-timeline-label-gap: 6px;
    --oart-timeline-line-colour: #424141;
    --oart-timeline-line-width: 2px;
    --oart-timeline-dot-size: 18px;
    --oart-timeline-dot-hover-scale: 1.28;
    --oart-timeline-transition: 280ms;

    --oart-timeline-bubble-w: 208px;
    --oart-timeline-bubble-h: 168px;
    --oart-timeline-bubble-gap: 26px;
    --oart-timeline-bubble-offset: 0px;
    --oart-timeline-bubble-scale: .72;

    --oart-timeline-tail-len: 162px;
    --oart-timeline-tail-w: 110px;
    --oart-timeline-tail-angle: 38deg;

    position: relative;
    width: 100%;
}

.oart-timeline__items {
    position: relative;
    display: flex;
    align-items: flex-start;
}

.oart-timeline__rail {
    position: absolute;
    top: calc(var(--oart-timeline-label-height) + (var(--oart-timeline-dot-size) - var(--oart-timeline-line-width)) / 2);
    right: calc(var(--oart-timeline-dot-size) / 2);
    left: calc(var(--oart-timeline-dot-size) / 2);
    z-index: 0;
    height: var(--oart-timeline-line-width);
    background: var(--oart-timeline-line-colour);
}

/* the line carries on past the last dot to the edge */
.oart-timeline--rail-full .oart-timeline__rail {
    right: 0;
}

.oart-timeline__item {
    /* the dot's centre — the anchor the whole bubble hangs off */
    --oart-tl-dot-cx: calc(var(--oart-timeline-dot-size) / 2);
    --oart-tl-dot-cy: calc(var(--oart-timeline-label-height) + var(--oart-timeline-dot-size) / 2);
    --oart-tl-angle: var(--oart-timeline-tail-angle);

    position: relative;
    z-index: 1;
    flex: 1 1 0;
    min-width: 0;
    color: inherit;
    text-decoration: none;
    outline: none;
}

/* the last bubble opens inward, or it hangs off the right edge */
.oart-timeline--mirror-last .oart-timeline__item:last-child {
    --oart-tl-angle: calc(180deg - var(--oart-timeline-tail-angle));
}

.oart-timeline__item--interactive {
    cursor: pointer;
}

.oart-timeline__label {
    display: flex;
    min-height: var(--oart-timeline-label-height);
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: var(--oart-timeline-label-gap);
    /* the label is an <a> when the step is linked; keep it looking like plain
       text and let the number and title own their own colours */
    color: inherit;
    text-decoration: none;
}

.oart-timeline__label--link {
    cursor: pointer;
}

.oart-timeline__number,
.oart-timeline__title {
    display: block;
    transition: color var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1);
}

.oart-timeline__number {
    color: var(--oart-tl-c);
}

.oart-timeline__dot {
    position: relative;
    z-index: 2;
    display: block;
    width: var(--oart-timeline-dot-size);
    height: var(--oart-timeline-dot-size);
    border-style: solid;
    border-radius: 50%;
    background-color: var(--oart-tl-c);
    transition: transform var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1), background-color var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1), border-color var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1);
}

.oart-timeline__item:hover .oart-timeline__dot,
.oart-timeline__item:focus-visible .oart-timeline__dot,
.oart-timeline__item.is-open .oart-timeline__dot {
    transform: scale(var(--oart-timeline-dot-hover-scale));
}

/* ---- attention on linked dots -------------------------------------------
   Two layers behind and around the dot: a filled halo and a thin ring. The
   Effect control picks which of the two runs and leaves the other at none.
   Nothing touches the dot's own transform, because that belongs to the hover
   scale above and an animation would win and freeze it. */
.oart-timeline {
    --oart-tl-attn-reach: 2.8;
    --oart-tl-attn-speed: 2.4s;

    --oart-tl-attn-halo-none: none;
    --oart-tl-attn-ring-none: none;
    --oart-tl-attn-halo-pulse: oart-tl-pulse;
    --oart-tl-attn-ring-pulse: none;
    --oart-tl-attn-halo-glow: oart-tl-glow;
    --oart-tl-attn-ring-glow: none;
    --oart-tl-attn-halo-radar: none;
    --oart-tl-attn-ring-radar: oart-tl-radar;
    --oart-tl-attn-halo-beacon: oart-tl-beacon;
    --oart-tl-attn-ring-beacon: none;
}

.oart-timeline__item--linked .oart-timeline__dot::before,
.oart-timeline__item--linked .oart-timeline__dot::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: 50%;
    opacity: 0;
    pointer-events: none;
    animation-duration: var(--oart-tl-attn-speed);
    animation-iteration-count: infinite;
    animation-timing-function: ease-out;
}

.oart-timeline__item--linked .oart-timeline__dot::before {
    background-color: var(--oart-tl-attn-c, var(--oart-tl-c));
    animation-name: var(--oart-tl-attn-halo, none);
}

.oart-timeline__item--linked .oart-timeline__dot::after {
    border: var(--oart-timeline-dot-border-width, 2px) solid var(--oart-tl-attn-c, var(--oart-tl-c));
    animation-name: var(--oart-tl-attn-ring, none);
}

/* Once someone is on the step they have found it, so stop waving. */
.oart-timeline__item--linked:hover .oart-timeline__dot::before,
.oart-timeline__item--linked:hover .oart-timeline__dot::after,
.oart-timeline__item--linked:focus-within .oart-timeline__dot::before,
.oart-timeline__item--linked:focus-within .oart-timeline__dot::after,
.oart-timeline__item--linked.is-open .oart-timeline__dot::before,
.oart-timeline__item--linked.is-open .oart-timeline__dot::after {
    animation-play-state: paused;
    opacity: 0;
}

@keyframes oart-tl-pulse {
    0%        { transform: scale(1); opacity: .5; }
    70%, 100% { transform: scale(var(--oart-tl-attn-reach)); opacity: 0; }
}

@keyframes oart-tl-glow {
    0%, 100% { transform: scale(1.1); opacity: .18; filter: blur(2px); }
    50%      { transform: scale(var(--oart-tl-attn-reach)); opacity: .45; filter: blur(6px); }
}

@keyframes oart-tl-radar {
    0%        { transform: scale(1); opacity: .85; }
    80%, 100% { transform: scale(var(--oart-tl-attn-reach)); opacity: 0; }
}

@keyframes oart-tl-beacon {
    0%, 45%, 100% { transform: scale(1); opacity: 0; }
    10%           { transform: scale(calc(var(--oart-tl-attn-reach) * .55)); opacity: .55; }
    22%           { transform: scale(1); opacity: 0; }
    32%           { transform: scale(calc(var(--oart-tl-attn-reach) * .75)); opacity: .4; }
}

.oart-timeline__bubble {
    /* where the dot falls inside the bubble's own box. Positioning off
       this instead of restating the trigonometry keeps the tail's apex,
       the bubble's placement and the pop-out origin all on one number. */
    --oart-tl-apex-x: calc(var(--oart-timeline-bubble-w) / 2 - cos(var(--oart-tl-angle)) * var(--oart-timeline-tail-len));
    --oart-tl-apex-y: calc(var(--oart-timeline-bubble-h) / 2 - sin(var(--oart-tl-angle)) * var(--oart-timeline-tail-len));

    position: absolute;
    z-index: 5;
    top: calc(var(--oart-tl-dot-cy) - var(--oart-tl-apex-y));
    left: calc(var(--oart-tl-dot-cx) - var(--oart-tl-apex-x));
    display: flex;
    width: var(--oart-timeline-bubble-w);
    height: var(--oart-timeline-bubble-h);
    box-sizing: border-box;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background-color: var(--oart-tl-c);
    /* Guarantees a stacking context, so the tail below can sit at
       z-index:-1 and paint above this background but behind the text.
       Without it the tail paints over the words it crosses. */
    isolation: isolate;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transform-origin: var(--oart-tl-apex-x) var(--oart-tl-apex-y);
    transform: translate3d(0, var(--oart-timeline-bubble-offset), 0) scale(var(--oart-timeline-bubble-scale));
    transition: opacity var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1), transform var(--oart-timeline-transition) cubic-bezier(.22, 1, .36, 1), visibility var(--oart-timeline-transition);
}

/* the tail: base buried at the bubble's centre, apex on the dot */
.oart-timeline__bubble::before {
    content: "";
    position: absolute;
    z-index: -1;
    top: 50%;
    left: 50%;
    width: var(--oart-timeline-tail-len);
    height: var(--oart-timeline-tail-w);
    margin-top: calc(var(--oart-timeline-tail-w) / -2);
    background-color: inherit;
    clip-path: polygon(0 0, 0 100%, 100% 50%);
    transform-origin: 0 50%;
    transform: rotate(calc(var(--oart-tl-angle) + 180deg));
}

.oart-timeline--hover-click .oart-timeline__item--interactive:hover .oart-timeline__bubble,
.oart-timeline__item--interactive:focus-visible .oart-timeline__bubble,
.oart-timeline__item--interactive.is-open .oart-timeline__bubble {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transform: translate3d(0, 0, 0) scale(1);
}

.oart-timeline__bubble-title,
.oart-timeline__bubble-content {
    width: 100%;
}

.oart-timeline__bubble-title,
.oart-timeline__bubble-content,
.oart-timeline__bubble-content > :first-child {
    margin-top: 0;
}

.oart-timeline__bubble-content > :last-child {
    margin-bottom: 0;
}

@media (max-width: 767px) {
    .oart-timeline__items {
        flex-direction: column;
    }

    .oart-timeline__rail {
        top: calc(var(--oart-timeline-dot-size) / 2);
        bottom: calc(var(--oart-timeline-dot-size) / 2);
        left: calc((var(--oart-timeline-dot-size) - var(--oart-timeline-line-width)) / 2);
        width: var(--oart-timeline-line-width);
        height: auto;
    }

    .oart-timeline__item {
        display: grid;
        width: 100%;
        grid-template-columns: var(--oart-timeline-dot-size) minmax(0, 1fr);
        grid-template-rows: auto auto;
        column-gap: var(--oart-timeline-bubble-gap);
    }

    .oart-timeline__label {
        min-height: 0;
        grid-column: 2;
        grid-row: 1;
    }

    .oart-timeline__dot {
        grid-column: 1;
        grid-row: 1;
    }

    /* The ellipse-and-tail geometry is drawn for a wide row: it hangs the
       bubble down and to one side of its dot. In a single narrow column
       there is nowhere for it to go, so the bubble drops into the grid
       under its own label and the tail comes off. */
    .oart-timeline__bubble {
        position: relative;
        top: auto;
        left: auto;
        display: none;
        width: 100%;
        height: auto;
        margin-top: var(--oart-timeline-bubble-gap);
        grid-column: 2;
        grid-row: 2;
        transform: none;
    }

    .oart-timeline__bubble::before {
        content: none;
    }

    .oart-timeline__item--interactive.is-open .oart-timeline__bubble,
    .oart-timeline__item--interactive:focus-visible .oart-timeline__bubble {
        display: flex;
        visibility: visible;
        opacity: 1;
        pointer-events: auto;
        transform: none;
    }
}

/* Only the lava blobs answer to the OS setting, and only when the widget's
   own "Respect Reduced Motion" control is switched on.

   The timeline's dot and bubble used to be frozen here too, unconditionally.
   They are hover transitions, a few hundred milliseconds of colour and scale
   that a visitor triggers deliberately, which is not the drifting, looping,
   large-area movement prefers-reduced-motion exists to stop. Freezing them
   bought nobody anything and left the widget looking broken on any phone with
   Reduce Motion switched on. */
@media (prefers-reduced-motion: reduce) {
    .oart-lava--reduce-motion .oart-lava__blob {
        animation: none !important;
        transition-duration: .01ms !important;
    }
}

/* ===================================================================
   Bubble menu
   Shapes come from Brand/Menu/SVG, used as masks so the colour stays a
   control.

   The round letter bubble has a fixed aspect ratio, so masking the artwork
   whole is exact.

   The flat pills have to stretch to whatever the menu says. Stretching the
   artwork would squash its rounded ends and its point, so instead the pill is
   masked in three pieces at natural scale: the two end caps keep their real
   geometry (one of them carries the point) and only a plain rectangle between
   them stretches. Artwork is 100.32 x 24.95 with a 21.17 tall body, so the
   full box is the pill height x 1.1786 and each cap slice is 22/24.95 of the
   box height.
   =================================================================== */

.oart-bmenu {
    --oart-bmenu-size: 74px;
    --oart-bmenu-gap-x: 16px;
    --oart-bmenu-gap-y: 22px;
    --oart-bmenu-letter: #000;
    --oart-bmenu-letter-x: 0px;
    --oart-bmenu-letter-y: 0.14em;
    --oart-bmenu-label-bg: #000;
    --oart-bmenu-label-text: #fff;
    --oart-bmenu-label-h: 26px;
    --oart-bmenu-label-px: 16px;
    --oart-bmenu-label-x: 10px;
    --oart-bmenu-label-y: 4px;
    --oart-bmenu-sub-bg: #FFA63A;
    --oart-bmenu-sub-text: #000;
    --oart-bmenu-sub-h: 24px;
    --oart-bmenu-sub-px: 14px;
    --oart-bmenu-sub-gap: 7px;
    --oart-bmenu-sub-y: 6px;
    --oart-bmenu-sub-stagger: 26px;
    --oart-bmenu-speed: 220ms;
    --oart-bmenu-hover-scale: 1.06;
    --oart-bmenu-hover-rotate: 0deg;
    --oart-bmenu-active-scale: 1;
    --oart-bmenu-active-rotate: 0deg;
    --oart-bmenu-sub-hover-scale: 1.04;
    --oart-bmenu-sub-hover-rotate: 0deg;
    --oart-bmenu-toggle: 26px;
    --oart-bmenu-toggle-colour: #000;
    --oart-bmenu-toggle-bar: 2px;
    --oart-bmenu-toggle-radius: 0px;
    /* breathing icon: how far each shape swells and shrinks, how long a full
       breath takes, and how far apart the four are allowed to drift (0..100) */
    --oart-bmenu-attn-up: 1.18;
    --oart-bmenu-attn-down: .88;
    --oart-bmenu-attn-dur: 2600ms;
    --oart-bmenu-attn-var: 55;
    --oart-bmenu-close: 26px;
    --oart-bmenu-close-colour: #000;
    --oart-bmenu-close-bar: 2px;
    --oart-bmenu-close-radius: 0px;
    --oart-bmenu-close-top: 20px;
    --oart-bmenu-close-right: 20px;
    --oart-bmenu-back: 26px;
    --oart-bmenu-back-colour: #000;
    --oart-bmenu-back-bar: 2px;
    --oart-bmenu-back-radius: 0px;
    --oart-bmenu-back-top: 20px;
    --oart-bmenu-back-left: 20px;
    /* How far down a drilled-into section sits. Clear of the back arrow by
       default, and follows it if the arrow is moved or resized. The Move a
       Section Down slider overrides this whole value once it is touched. */
    --oart-bmenu-drill-top: calc(var(--oart-bmenu-back-top) + var(--oart-bmenu-back) + var(--oart-bmenu-gap-y));
    --oart-bmenu-colour: #9B5DF5;

    --oart-bmenu-bubble-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/svg%3E");

    /* left artwork, cropped to its two ends */
    --oart-bmenu-pill-l-tail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-bmenu-pill-l-end: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");

    /* Middle of the artwork: straight sided, so it stretches losslessly.
       preserveAspectRatio='none' is essential - an SVG defaults to 'meet',
       which FITS its viewBox inside the viewport and centres it rather than
       stretching. Without it, CSS asks for a wide middle and the SVG quietly
       paints a narrow band in the centre, leaving gaps beside the caps. The
       caps do not need it: mask-size 'auto 100%' gives them their own aspect. */
    --oart-bmenu-pill-mid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' viewBox='40 0 20 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");

    /* right artwork, cropped to its two ends */
    --oart-bmenu-pill-r-end: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oart-bmenu-pill-r-tail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");

    position: relative;
    /* flex, not block: an inline-flex toggle inside a block sits on a text
       baseline, and the line box's leading shows up as unexplained space
       around the hamburger. */
    display: flex;
    align-items: center;
}

.oart-bmenu__sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.oart-bmenu__empty {
    padding: 14px 18px;
    border: 1px dashed currentColor;
    border-radius: 6px;
    font-size: 12px;
    opacity: .75;
}

.oart-bmenu__list {
    display: flex;
    align-items: center;
    gap: var(--oart-bmenu-gap-x);
    list-style: none;
    margin: 0;
    padding: 0;
}

.oart-bmenu__item {
    position: relative;
    display: flex;
    align-items: center;
}

/* --- the round letter bubble --- */
.oart-bmenu__bubble {
    position: relative;
    display: grid;
    place-items: center;
    flex: none;
    width: var(--oart-bmenu-size);
    aspect-ratio: 81.84 / 74.44;
    background-color: var(--oart-bmenu-colour);
    -webkit-mask: var(--oart-bmenu-bubble-mask) center / contain no-repeat;
    mask: var(--oart-bmenu-bubble-mask) center / contain no-repeat;
    text-decoration: none;
    transition: transform var(--oart-bmenu-speed) ease,
                background-color var(--oart-bmenu-speed) ease;
}

/* Amatry's line box sits the baseline low, so a plain centre leaves the cap
   riding high in the bubble. Nudge it down; both axes are controls because the
   right value depends on the font. */
.oart-bmenu__letter {
    color: var(--oart-bmenu-letter);
    line-height: 1;
    transform: translate(var(--oart-bmenu-letter-x), var(--oart-bmenu-letter-y));
    pointer-events: none;
}

/* Active (the current page's bubble). Same fallback trick as hover, so an
   unset control keeps the resting look. Placed before the hover rules in the
   source so hovering the active bubble still shows the hover state. */
.oart-bmenu__item--active .oart-bmenu__bubble {
    transform: scale(var(--oart-bmenu-active-scale)) rotate(var(--oart-bmenu-active-rotate));
    background-color: var(--oart-bmenu-active-colour, var(--oart-bmenu-colour));
}

.oart-bmenu__item--active .oart-bmenu__letter {
    color: var(--oart-bmenu-letter-active, var(--oart-bmenu-letter));
}

/* Hover: the fallbacks mean an unset control simply keeps the resting look,
   so a colour only changes if it has actually been chosen. */
.oart-bmenu__item:hover .oart-bmenu__bubble,
.oart-bmenu__bubble:focus-visible {
    transform: scale(var(--oart-bmenu-hover-scale)) rotate(var(--oart-bmenu-hover-rotate));
    background-color: var(--oart-bmenu-hover-colour, var(--oart-bmenu-colour));
}

.oart-bmenu__item:hover .oart-bmenu__letter,
.oart-bmenu__bubble:focus-visible .oart-bmenu__letter {
    color: var(--oart-bmenu-letter-hover, var(--oart-bmenu-letter));
}

.oart-bmenu__letter {
    transition: color var(--oart-bmenu-speed) ease;
}

/* --- the flat pills (labels and sub items) --- */
.oart-bmenu__label,
.oart-bmenu__sub {
    --bm-box: calc(var(--bm-h) * 1.1786);
    /* what each end mask crops from the artwork */
    --bm-cap: calc(var(--bm-box) * 0.8818);
    /* Where the stretching middle starts. It must clear the curved ends
       (they only reach full height at 0.667 of the box) but still overlap the
       end masks (which cover 0.8818). Butting them up exactly leaves a
       hairline gap on sub-pixel widths and the background shows through as a
       white line, so sit between the two and overlap. */
    --bm-mid: calc(var(--bm-box) * 0.75);

    position: relative;
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    height: var(--bm-box);
    min-width: calc(var(--bm-cap) * 2);
    padding: 0 var(--bm-px) calc(var(--bm-box) - var(--bm-h));
    white-space: nowrap;
    line-height: 1;
    text-decoration: none;

    /* All three layers come from the same artwork and scale to the same 100%
       box height, so their top and bottom edges coincide exactly. A CSS
       rectangle here instead leaves a visible step where it meets the caps. */
    -webkit-mask-image: var(--bm-cap-a), var(--bm-cap-b), var(--oart-bmenu-pill-mid);
    mask-image: var(--bm-cap-a), var(--bm-cap-b), var(--oart-bmenu-pill-mid);
    -webkit-mask-repeat: no-repeat, no-repeat, no-repeat;
    mask-repeat: no-repeat, no-repeat, no-repeat;
    -webkit-mask-position: left top, right top, var(--bm-mid) top;
    mask-position: left top, right top, var(--bm-mid) top;
    -webkit-mask-size: auto 100%, auto 100%, calc(100% - var(--bm-mid) * 2) 100%;
    mask-size: auto 100%, auto 100%, calc(100% - var(--bm-mid) * 2) 100%;
}

/* point at the bottom left */
.oart-bmenu--tail-left {
    --bm-cap-a: var(--oart-bmenu-pill-l-tail);
    --bm-cap-b: var(--oart-bmenu-pill-l-end);
}

/* point at the bottom right */
.oart-bmenu--tail-right {
    --bm-cap-a: var(--oart-bmenu-pill-r-end);
    --bm-cap-b: var(--oart-bmenu-pill-r-tail);
}

.oart-bmenu__label {
    --bm-h: var(--oart-bmenu-label-h);
    --bm-px: var(--oart-bmenu-label-px);
    /* default point direction; the breakpoints below flip it per side */
    --bm-cap-a: var(--oart-bmenu-pill-l-tail);
    --bm-cap-b: var(--oart-bmenu-pill-l-end);
    position: absolute;
    z-index: 2;
    background-color: var(--oart-bmenu-label-bg);
    color: var(--oart-bmenu-label-text);
    pointer-events: none;
}

.oart-bmenu[data-label-from-item="1"] .oart-bmenu__label {
    color: var(--oart-bmenu-colour);
}

.oart-bmenu__sub {
    --bm-h: var(--oart-bmenu-sub-h);
    --bm-px: var(--oart-bmenu-sub-px);
    background-color: var(--oart-bmenu-sub-bg);
    color: var(--oart-bmenu-sub-text);
}

.oart-bmenu[data-sub-from-item="1"] .oart-bmenu__sub {
    background-color: var(--oart-bmenu-colour);
}

.oart-bmenu__sub {
    transition: transform var(--oart-bmenu-speed) ease,
                background-color var(--oart-bmenu-speed) ease,
                color var(--oart-bmenu-speed) ease;
}

.oart-bmenu__sub:hover,
.oart-bmenu__sub:focus-visible {
    transform: scale(var(--oart-bmenu-sub-hover-scale)) rotate(var(--oart-bmenu-sub-hover-rotate));
    background-color: var(--oart-bmenu-sub-hover-bg, var(--oart-bmenu-sub-bg));
    color: var(--oart-bmenu-sub-hover-text, var(--oart-bmenu-sub-text));
}

/* when the pill takes its colour from the item, the hover fallback must too */
.oart-bmenu[data-sub-from-item="1"] .oart-bmenu__sub:hover,
.oart-bmenu[data-sub-from-item="1"] .oart-bmenu__sub:focus-visible {
    background-color: var(--oart-bmenu-sub-hover-bg, var(--oart-bmenu-colour));
}

/* --- sub items --- */
.oart-bmenu__subs {
    position: absolute;
    z-index: 1;
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--oart-bmenu-sub-gap);
}

.oart-bmenu__sub-item[data-odd="1"] {
    margin-left: var(--oart-bmenu-sub-stagger);
}

/* the reference alternates which end carries the point */
.oart-bmenu__sub-item[data-odd="0"] .oart-bmenu__sub {
    --bm-cap-a: var(--oart-bmenu-pill-r-end);
    --bm-cap-b: var(--oart-bmenu-pill-r-tail);
}

.oart-bmenu__sub-item[data-odd="1"] .oart-bmenu__sub {
    --bm-cap-a: var(--oart-bmenu-pill-l-tail);
    --bm-cap-b: var(--oart-bmenu-pill-l-end);
}

.oart-bmenu__subs-toggle {
    position: absolute;
    inset: 0;
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
    display: none;
}

/* ===================== DESKTOP ===================== */
@media (min-width: 768px) {
    .oart-bmenu__toggle { display: none; }

    /* The panel is only a panel on mobile, so its close and back buttons have
       nothing to act on up here. A <button> shows by default, so this has to
       be said. */
    .oart-bmenu__close,
    .oart-bmenu__back { display: none; }

    .oart-bmenu__panel {
        background: none !important;
        padding: 0 !important;
    }

    .oart-bmenu__panel-logo { display: none; }

    .oart-bmenu__label {
        left: calc(100% - var(--oart-bmenu-label-x));
        bottom: calc(100% + var(--oart-bmenu-label-y));
        opacity: 0;
        transform: translateY(6px);
        transition: opacity var(--oart-bmenu-speed) ease, transform var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu__item:hover .oart-bmenu__label,
    .oart-bmenu__item:focus-within .oart-bmenu__label {
        opacity: 1;
        transform: none;
    }

    /* The current page keeps its label showing, when the Active state's
       "Show Label When Active" is on. */
    .oart-bmenu[data-active-label="1"] .oart-bmenu__item--active .oart-bmenu__label {
        opacity: 1;
        transform: none;
    }

    /* The menu sits at the right edge of the header, so the last item's label
       would open past the viewport and push the whole page sideways - an
       absolutely positioned box still counts towards scrollable overflow even
       while it is hidden. Open that one leftwards, point flipped to match. */
    .oart-bmenu__item:last-child .oart-bmenu__label {
        left: auto;
        right: calc(100% - var(--oart-bmenu-label-x));
        --bm-cap-a: var(--oart-bmenu-pill-r-end);
        --bm-cap-b: var(--oart-bmenu-pill-r-tail);
    }

    .oart-bmenu__subs {
        top: calc(100% + var(--oart-bmenu-sub-y));
        left: 0;
        opacity: 0;
        visibility: hidden;
        transform: translateY(6px);
        transition: opacity var(--oart-bmenu-speed) ease,
                    transform var(--oart-bmenu-speed) ease,
                    visibility var(--oart-bmenu-speed);
    }

    .oart-bmenu[data-subs-trigger="hover"] .oart-bmenu__item:hover .oart-bmenu__subs,
    .oart-bmenu[data-subs-trigger="hover"] .oart-bmenu__item:focus-within .oart-bmenu__subs,
    .oart-bmenu__item.is-open .oart-bmenu__subs {
        opacity: 1;
        visibility: visible;
        transform: none;
    }
}

/* ===================== MOBILE ===================== */
@media (max-width: 767px) {
    .oart-bmenu__toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        border: 0;
        padding: 0;
        cursor: pointer;
        line-height: 0;
        color: var(--oart-bmenu-toggle-colour);
        background-color: var(--oart-bmenu-toggle-bg, transparent);
        border-radius: var(--oart-bmenu-toggle-radius);
        transition: background-color var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu__toggle:hover,
    .oart-bmenu__toggle:focus-visible {
        background-color: var(--oart-bmenu-toggle-bg-hover, var(--oart-bmenu-toggle-bg, transparent));
        color: var(--oart-bmenu-toggle-colour-hover, var(--oart-bmenu-toggle-colour));
    }

    /* --- active: the menu is open ---
       After :hover so opening the menu wins over the finger still resting on
       the button, which is the normal state on a phone. */
    .oart-bmenu.is-open .oart-bmenu__toggle,
    .oart-bmenu.is-open .oart-bmenu__toggle:hover {
        background-color: var(--oart-bmenu-toggle-bg-active, var(--oart-bmenu-toggle-bg, transparent));
        color: var(--oart-bmenu-toggle-colour-active, var(--oart-bmenu-toggle-colour));
    }

    /* --- focus ---
       Tapping the button leaves the browser's own blue box drawn around it,
       and it sits there after the menu is closed again. Turned off here.

       It is NOT simply deleted: someone moving through the page by keyboard
       has nothing else telling them where they are. :focus-visible fires for
       keyboard use and not for a tap or a click, so the ring below is the
       replacement and a finger never sees it.

       tap-highlight is the separate grey flash iOS and Android paint over a
       button the moment it is touched. */
    .oart-bmenu__toggle {
        -webkit-tap-highlight-color: transparent;
    }

    .oart-bmenu__toggle:focus { outline: none; }

    .oart-bmenu__toggle:focus-visible {
        outline: 2px solid var(--oart-bmenu-toggle-focus, #9B5DF5);
        outline-offset: 4px;
        border-radius: var(--oart-bmenu-toggle-radius);
    }

    .oart-bmenu__toggle:hover .oart-bmenu__bar,
    .oart-bmenu__toggle:focus-visible .oart-bmenu__bar {
        background-color: var(--oart-bmenu-toggle-colour-hover, var(--oart-bmenu-toggle-colour));
    }

    /* custom icon, when one is set: swap it for the hover version */
    .oart-bmenu__toggle-icon {
        display: flex;
        width: var(--oart-bmenu-toggle);
        height: auto;
        line-height: 0;
    }

    .oart-bmenu__toggle-icon svg,
    .oart-bmenu__toggle-icon img {
        width: 100%;
        height: auto;
        display: block;
    }

    /* --- one colour per shape in the icon ---
       Falls back to currentColor, which the button already sets from
       --oart-bmenu-toggle-colour (and its hover version), so an icon with no
       per-shape colours set behaves exactly as it did and still follows the
       Line Colour control. nth-of-type counts <path> siblings, which is what
       the JS produces when it splits a single-path file. */
    .oart-bmenu__toggle-icon svg path:nth-of-type(1) { fill: var(--oart-bmenu-blob-1, currentColor); }
    .oart-bmenu__toggle-icon svg path:nth-of-type(2) { fill: var(--oart-bmenu-blob-2, currentColor); }
    .oart-bmenu__toggle-icon svg path:nth-of-type(3) { fill: var(--oart-bmenu-blob-3, currentColor); }
    .oart-bmenu__toggle-icon svg path:nth-of-type(4) { fill: var(--oart-bmenu-blob-4, currentColor); }

    /* --- breathing ---
       transform-origin is written per shape by the JS, at that shape's own
       point, so it swells outwards and the point stays put. transform-box must
       be view-box or the origin would be measured against the shape's own
       bounding box instead of the icon's coordinate system.

       Duration and delay are also per shape (the JS scatters them), which is
       why neither is set here. */
    /* The artwork already fills its own coordinate box edge to edge, so a
       swelling bubble goes outside it: at the default 1.18 the four reach
       x -21 and x 249 against a box of 0 to 230.9, and past the top and bottom
       too. Browsers clip the outermost <svg> by default, which sliced a flat
       edge off each bubble at the top of every breath. Nothing else in the
       chain clips, so releasing the svg is the whole fix, and it leaves the
       icon exactly the size it was at rest.

       Scoped to the breathing case, so a still custom icon is untouched. */
    .oart-bmenu[data-toggle-attn="1"] .oart-bmenu__toggle-icon,
    .oart-bmenu[data-toggle-attn="1"] .oart-bmenu__toggle-icon svg {
        overflow: visible;
    }

    .oart-bmenu[data-toggle-attn="1"] .oart-bmenu__toggle-icon svg path {
        transform-box: view-box;
        animation-name: oart-bmenu-breathe;
        animation-timing-function: ease-in-out;
        animation-iteration-count: infinite;
        will-change: transform;
    }

    /* Nothing breathing behind an open menu: the panel covers the icon, and a
       cross that is still pulsing reads as a mistake. */
    .oart-bmenu.is-open .oart-bmenu__toggle-icon svg path {
        animation: none;
        transform: none;
    }

    .oart-bmenu__toggle-icon--hover { display: none; }

    .oart-bmenu__toggle:hover .oart-bmenu__toggle-icon--has-hover.oart-bmenu__toggle-icon--normal,
    .oart-bmenu__toggle:focus-visible .oart-bmenu__toggle-icon--has-hover.oart-bmenu__toggle-icon--normal {
        display: none;
    }

    .oart-bmenu__toggle:hover .oart-bmenu__toggle-icon--hover,
    .oart-bmenu__toggle:focus-visible .oart-bmenu__toggle-icon--hover {
        display: flex;
    }

    .oart-bmenu__toggle-text {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .oart-bmenu__toggle-box {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        width: var(--oart-bmenu-toggle);
        height: calc(var(--oart-bmenu-toggle) * .72);
    }

    .oart-bmenu__bar {
        display: block;
        height: var(--oart-bmenu-toggle-bar);
        border-radius: var(--oart-bmenu-toggle-bar);
        background-color: var(--oart-bmenu-toggle-colour);
        transition: transform var(--oart-bmenu-speed) ease,
                    opacity var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu.is-open .oart-bmenu__bar:nth-child(1) {
        transform: translateY(calc(var(--oart-bmenu-toggle) * .34)) rotate(45deg);
    }
    .oart-bmenu.is-open .oart-bmenu__bar:nth-child(2) { opacity: 0; }
    .oart-bmenu.is-open .oart-bmenu__bar:nth-child(3) {
        transform: translateY(calc(var(--oart-bmenu-toggle) * -.34)) rotate(-45deg);
    }

    .oart-bmenu__panel {
        position: fixed;
        inset: 0;
        z-index: 9999;
        display: flex;
        flex-direction: column;
        overflow-y: auto;
        opacity: 0;
        visibility: hidden;
        transition: opacity var(--oart-bmenu-speed) ease, visibility var(--oart-bmenu-speed);
    }

    .oart-bmenu.is-open .oart-bmenu__panel {
        opacity: 1;
        visibility: visible;
    }

    /* Sits over the open panel. The hamburger animates into a cross, but the
       panel covers it once open, so on a phone this is the only way out other
       than picking something. Absolute against the panel, which is the full
       screen here. */
    .oart-bmenu__close {
        position: absolute;
        top: var(--oart-bmenu-close-top);
        right: var(--oart-bmenu-close-right);
        z-index: 2;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        border: 0;
        padding: 0;
        cursor: pointer;
        line-height: 0;
        color: var(--oart-bmenu-close-colour);
        background-color: var(--oart-bmenu-close-bg, transparent);
        border-radius: var(--oart-bmenu-close-radius);
        transition: background-color var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu__close:hover,
    .oart-bmenu__close:focus-visible {
        background-color: var(--oart-bmenu-close-bg-hover, var(--oart-bmenu-close-bg, transparent));
    }

    .oart-bmenu__close-icon {
        display: flex;
        width: var(--oart-bmenu-close);
        height: auto;
        line-height: 0;
    }

    .oart-bmenu__close-icon svg,
    .oart-bmenu__close-icon img {
        width: 100%;
        height: auto;
        display: block;
    }

    .oart-bmenu__close-box {
        position: relative;
        display: block;
        width: var(--oart-bmenu-close);
        height: var(--oart-bmenu-close);
    }

    /* Two bars crossed through the middle. Positioned off the centre line so
       the thickness control cannot push the cross off centre. */
    .oart-bmenu__close-bar {
        position: absolute;
        top: 50%;
        left: 0;
        width: 100%;
        height: var(--oart-bmenu-close-bar);
        margin-top: calc(var(--oart-bmenu-close-bar) / -2);
        border-radius: var(--oart-bmenu-close-bar);
        background-color: var(--oart-bmenu-close-colour);
        transition: background-color var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu__close-bar:nth-child(1) { transform: rotate(45deg); }
    .oart-bmenu__close-bar:nth-child(2) { transform: rotate(-45deg); }

    .oart-bmenu__close:hover .oart-bmenu__close-bar,
    .oart-bmenu__close:focus-visible .oart-bmenu__close-bar {
        background-color: var(--oart-bmenu-close-colour-hover, var(--oart-bmenu-close-colour));
    }

    .oart-bmenu__panel-logo { margin-bottom: auto; }
    .oart-bmenu__panel-logo img { display: block; height: auto; }

    .oart-bmenu__list {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: var(--oart-bmenu-gap-y);
        margin: auto 0;
        width: 100%;
    }

    .oart-bmenu__item { width: 100%; justify-content: center; }

    /* Above everything. An item that has sub-menus raises its own bubble to
       z-index 4 further down, and that was covering the point on the label
       beside it. The label is pointer-events:none, so sitting on top cannot
       steal a tap from the bubble or the subs toggle underneath it. */
    .oart-bmenu__label { top: var(--oart-bmenu-label-y); z-index: 5; }

    /* label to the left of the bubble, point aiming back at it */
    .oart-bmenu__item[data-side="left"] .oart-bmenu__label {
        right: calc(50% + var(--oart-bmenu-size) / 2 - var(--oart-bmenu-label-x));
        --bm-cap-a: var(--oart-bmenu-pill-r-end);
        --bm-cap-b: var(--oart-bmenu-pill-r-tail);
    }

    /* label to the right of the bubble */
    .oart-bmenu__item[data-side="right"] .oart-bmenu__label {
        left: calc(50% + var(--oart-bmenu-size) / 2 - var(--oart-bmenu-label-x));
        --bm-cap-a: var(--oart-bmenu-pill-l-tail);
        --bm-cap-b: var(--oart-bmenu-pill-l-end);
    }

    .oart-bmenu__subs {
        top: calc(50% + var(--oart-bmenu-sub-y));
        display: none;
    }

    .oart-bmenu__item.is-open .oart-bmenu__subs { display: flex; }

    .oart-bmenu__item[data-side="left"] .oart-bmenu__subs {
        right: calc(50% + var(--oart-bmenu-size) / 2 - var(--oart-bmenu-label-x));
        align-items: flex-end;
    }
    .oart-bmenu__item[data-side="right"] .oart-bmenu__subs {
        left: calc(50% + var(--oart-bmenu-size) / 2 - var(--oart-bmenu-label-x));
        align-items: flex-start;
    }

    .oart-bmenu__item--has-subs .oart-bmenu__subs-toggle {
        display: block;
        z-index: 3;
    }
    .oart-bmenu__item--has-subs .oart-bmenu__bubble { position: relative; z-index: 4; }

    /* ---- one section at a time ------------------------------------------
       Tapping a bubble that has sub items drills into it. Everything else
       drops away, that bubble and its label stay exactly as they were and
       become the heading, and the sub items line up underneath instead of
       floating beside the bubble on top of their neighbours, which is what
       made this a scramble on a phone. */
    .oart-bmenu.is-drilled .oart-bmenu__item:not(.is-current) { display: none; }

    /* The full menu fills the screen so it sits centred. A single section is
       much shorter, and centring it leaves a dead band above the heading, so
       it starts from the top and is pushed down by its own control instead. */
    .oart-bmenu.is-drilled .oart-bmenu__list {
        margin: 0;
        justify-content: flex-start;
        padding-top: var(--oart-bmenu-drill-top);
    }

    .oart-bmenu.is-drilled .oart-bmenu__item.is-current {
        flex-direction: column;
        gap: calc(var(--oart-bmenu-sub-gap) + var(--oart-bmenu-sub-y));
    }

    /* Into normal flow under the bubble. static ignores the per-side left and
       right offsets set above, so those do not need undoing one by one. */
    .oart-bmenu.is-drilled .oart-bmenu__item.is-current .oart-bmenu__subs {
        position: static;
        display: flex;
        align-items: center;
    }

    /* The alternating indent reads as a scatter once the list is centred. The
       alternating point on the pills carries that language on its own. */
    .oart-bmenu.is-drilled .oart-bmenu__item.is-current .oart-bmenu__sub-item {
        margin-left: 0;
    }

    /* The heading is a link to its own page, so the full-item tap target that
       drilled us in here must not stay sitting over it. */
    .oart-bmenu.is-drilled .oart-bmenu__item.is-current .oart-bmenu__subs-toggle {
        display: none;
    }

    /* ---- back to the main list ---- */
    .oart-bmenu__back {
        position: absolute;
        top: var(--oart-bmenu-back-top);
        left: var(--oart-bmenu-back-left);
        z-index: 2;
        display: none;
        align-items: center;
        justify-content: center;
        border: 0;
        padding: 0;
        cursor: pointer;
        line-height: 0;
        color: var(--oart-bmenu-back-colour);
        background-color: var(--oart-bmenu-back-bg, transparent);
        border-radius: var(--oart-bmenu-back-radius);
        transition: background-color var(--oart-bmenu-speed) ease,
                    color var(--oart-bmenu-speed) ease;
    }

    .oart-bmenu.is-drilled .oart-bmenu__back { display: inline-flex; }

    .oart-bmenu__back:hover,
    .oart-bmenu__back:focus-visible {
        color: var(--oart-bmenu-back-colour-hover, var(--oart-bmenu-back-colour));
        background-color: var(--oart-bmenu-back-bg-hover, var(--oart-bmenu-back-bg, transparent));
    }

    .oart-bmenu__back-icon {
        display: flex;
        width: var(--oart-bmenu-back);
        height: auto;
        line-height: 0;
    }

    .oart-bmenu__back-icon svg,
    .oart-bmenu__back-icon img {
        width: 100%;
        height: auto;
        display: block;
    }

    .oart-bmenu__back-box {
        position: relative;
        display: block;
        width: var(--oart-bmenu-back);
        height: var(--oart-bmenu-back);
    }

    /* A left chevron is two sides of a square turned 45 degrees. Drawn rather
       than shipped as an icon so its thickness and colour stay controls. */
    .oart-bmenu__back-box::before {
        content: '';
        position: absolute;
        top: 50%;
        left: 55%;
        width: 55%;
        height: 55%;
        border-left: var(--oart-bmenu-back-bar) solid currentColor;
        border-bottom: var(--oart-bmenu-back-bar) solid currentColor;
        transform: translate(-50%, -50%) rotate(45deg);
    }
}

/* The menu's motion is hover transitions and the panel opening, both of them
   responses to a deliberate tap or hover rather than movement that happens at
   a visitor. It no longer switches itself off on a device asking to limit
   animation, which was leaving the menu inert on any phone with Reduce Motion
   on and giving nothing back in exchange. */

/* ===================================================================
   Chat
   Same brand speech bubble as the menu, flipped so the point sits at the top,
   and masked in three pieces for the same reason: the ends and the point keep
   their real geometry while only the middle stretches to fit the message.
   Artwork 100.32 x 24.95, body 21.17 tall -> box = height x 1.1786, the point
   overhangs the top by the difference, cap slice = 0.8818 of the box, and the
   stretching middle sits at 0.75 so it overlaps the caps instead of butting up
   against them (butting up leaves hairline gaps on fractional widths).
   =================================================================== */

.oart-chat {
    --oart-chat-row-gap: 18px;
    --oart-chat-max: 78%;

    --oart-chat-right-bg: #000;
    --oart-chat-right-text: #FF6A63;
    --oart-chat-right-h: 52px;
    --oart-chat-right-px: 30px;
    --oart-chat-right-inset: 0px;
    --oart-chat-right-dur: 420ms;
    --oart-chat-right-rise: 14px;
    --oart-chat-right-scale: .82;

    --oart-chat-left-bg: #000;
    --oart-chat-left-text: #FF6A63;
    --oart-chat-left-h: 52px;
    --oart-chat-left-px: 30px;
    --oart-chat-left-inset: 0px;
    --oart-chat-left-dur: 420ms;
    --oart-chat-left-rise: 14px;
    --oart-chat-left-scale: .82;

    --oart-chat-typing-h: 38px;
    --oart-chat-typing-dot: #FF6A63;
    --oart-chat-typing-dot-size: 7px;


    /* Just the point, cropped from the artwork. The body is a CSS stadium,
       which is exact at any size, so only this needs to be artwork. */
    --oart-pt-bl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 6 18 18.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-pt-br: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='82.32 6 18 18.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oart-pt-tl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-pt-tr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='82.32 0 18 18.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/g%3E%3C/svg%3E");

    display: block;
}

.oart-chat__empty {
    padding: 14px 18px;
    border: 1px dashed currentColor;
    border-radius: 6px;
    font-size: 12px;
    opacity: .75;
}

.oart-chat__list {
    display: flex;
    flex-direction: column;
    gap: var(--oart-chat-row-gap);
    list-style: none;
    margin: 0;
    padding: 0;
}

.oart-chat__row {
    position: relative;
    display: flex;
    min-width: 0;
    padding-top: calc(var(--oart-chat-right-h) * 0.1786);   /* the point overhangs */
}

.oart-chat__row--right {
    justify-content: flex-end;
    padding-right: var(--oart-chat-right-inset);
}

.oart-chat__row--left {
    justify-content: flex-start;
    padding-left: var(--oart-chat-left-inset);
    /* The base rule sizes the point's headroom from the RIGHT height, which is
       wrong the moment the two sides are set to different heights. The chat
       form on the home page runs right 44px / left 52px, so every left row was
       1.43px short and its point clipped into the row above. Rows with no side
       (the form's send row) keep the base rule, which is what they want. */
    padding-top: calc(var(--oart-chat-left-h) * 0.1786);
}

/* --- the bubble ---
   The artwork's body is a stadium: its cap radius is exactly half its height.
   CSS reproduces that exactly at ANY width and ANY height, so the body is just
   a border-radius and only the point is artwork, overlaid on top.

   The previous version masked the whole shape in three pieces. That only held
   for a single line: the end caps were sized `auto 100%`, so as soon as a
   message wrapped, the bubble grew taller, the caps scaled up with it and
   detached from a middle still measured off the single-line height. A chat has
   to wrap, so the shape must not depend on the height staying put. */
.oart-chat__bubble {
    --pt-out: calc(var(--bm-h) * 0.1786);   /* how far the point sticks out */

    position: relative;
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    max-width: var(--oart-chat-max);
    min-height: var(--bm-h);
    /* The vertical padding is the set height minus one line box, halved. That
       makes a single-line bubble land exactly on the set height AND every extra
       line add exactly one line box, so the space above and below the text is
       the same whatever the message length.

       The old `calc(var(--bm-h) * 0.16)` fought min-height and lost. On one
       line min-height was the binding constraint, so the declared padding never
       applied at all: the real space was 15.65px, not the 8.32px it asked for.
       The moment a message wrapped, min-height stopped binding, the declared
       padding took over and the space halved, leaving every wrapped bubble
       14.66px too short and visibly squashed. */
    padding-inline: var(--bm-px);
    padding-block: max(0px, calc((var(--bm-h) - 1.15em) / 2));
    border-radius: calc(var(--bm-h) / 2);
    line-height: 1.15;
    /* Guarantees a stacking context, so the point below can sit at z-index:-1
       and paint above this background but behind the text. Without it the
       point paints over the text and eats the first or last few characters. */
    isolation: isolate;

    /* resting state, before the message arrives */
    opacity: 0;
    transform: translateY(var(--bm-rise)) scale(var(--bm-scale));
    transform-origin: var(--bm-origin) top;
    will-change: transform, opacity;
}

/* the point: size follows the bubble height, so a three-line message keeps
   exactly the same point as a one-line message */
.oart-chat__bubble::before {
    content: "";
    position: absolute;
    /* An absolutely positioned pseudo-element paints ABOVE in-flow text, so
       without this the point covers whichever characters it overlaps. -1 puts
       it after the bubble's background (same colour, invisible join) but
       before the text. */
    z-index: -1;
    top: calc(var(--pt-out) * -1);
    width: calc(var(--bm-h) * 0.8503);
    height: calc(var(--bm-h) * 0.8951);
    background-color: inherit;
    -webkit-mask: var(--bm-pt) center / contain no-repeat;
    mask: var(--bm-pt) center / contain no-repeat;
}

/* `1lh` is the element's real line box, so this stays correct even if the
   typography control is given a line height other than this file's 1.15. The
   1.15em above is the fallback for browsers without the unit, and matches the
   line-height declared on .oart-chat__bubble. */
@supports (padding-block: 1lh) {
    .oart-chat__bubble {
        padding-block: max(0px, calc((var(--bm-h) - 1lh) / 2));
    }
}

.oart-chat__row--no-point .oart-chat__bubble::before { content: none; }

.oart-chat__row--right .oart-chat__bubble {
    --bm-h: var(--oart-chat-right-h);
    --bm-px: var(--oart-chat-right-px);
    --bm-rise: var(--oart-chat-right-rise);
    --bm-scale: var(--oart-chat-right-scale);
    --bm-origin: right;
    --bm-pt: var(--oart-pt-tr);
    background-color: var(--oart-chat-right-bg);
    color: var(--oart-chat-right-text);
    transition: opacity var(--oart-chat-right-dur) cubic-bezier(.22, 1.4, .36, 1),
                transform var(--oart-chat-right-dur) cubic-bezier(.22, 1.4, .36, 1);
}

.oart-chat__row--right .oart-chat__bubble::before { right: 0; }

.oart-chat__row--left .oart-chat__bubble {
    --bm-h: var(--oart-chat-left-h);
    --bm-px: var(--oart-chat-left-px);
    --bm-rise: var(--oart-chat-left-rise);
    --bm-scale: var(--oart-chat-left-scale);
    --bm-origin: left;
    --bm-pt: var(--oart-pt-tl);
    background-color: var(--oart-chat-left-bg);
    color: var(--oart-chat-left-text);
    transition: opacity var(--oart-chat-left-dur) cubic-bezier(.22, 1.4, .36, 1),
                transform var(--oart-chat-left-dur) cubic-bezier(.22, 1.4, .36, 1);
}

.oart-chat__row--left .oart-chat__bubble::before { left: 0; }

.oart-chat__row.is-in .oart-chat__bubble {
    opacity: 1;
    transform: none;
}

/* --- typing indicator --- */
.oart-chat__typing {
    position: absolute;
    bottom: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--oart-chat-typing-dot-size) * .8);
    box-sizing: border-box;
    height: var(--oart-chat-typing-h);
    padding: 0 calc(var(--oart-chat-typing-dot-size) * 2);
    border-radius: 999px;
    opacity: 0;
    transform: scale(.8);
    transition: opacity 220ms ease, transform 220ms cubic-bezier(.22, 1.4, .36, 1);
    pointer-events: none;
}

.oart-chat__row--right .oart-chat__typing {
    right: var(--oart-chat-right-inset);
    transform-origin: right bottom;
    background-color: var(--oart-chat-typing-bg, var(--oart-chat-right-bg));
}

.oart-chat__row--left .oart-chat__typing {
    left: var(--oart-chat-left-inset);
    transform-origin: left bottom;
    background-color: var(--oart-chat-typing-bg, var(--oart-chat-left-bg));
}

.oart-chat__row.is-typing .oart-chat__typing {
    opacity: 1;
    transform: none;
}

.oart-chat__typing i {
    display: block;
    width: var(--oart-chat-typing-dot-size);
    height: var(--oart-chat-typing-dot-size);
    border-radius: 50%;
    background-color: var(--oart-chat-typing-dot);
    opacity: .4;
}

.oart-chat__row.is-typing .oart-chat__typing i {
    animation: oart-chat-dot 1.1s ease-in-out infinite;
}

.oart-chat__row.is-typing .oart-chat__typing i:nth-child(2) { animation-delay: .15s; }
.oart-chat__row.is-typing .oart-chat__typing i:nth-child(3) { animation-delay: .3s; }

@keyframes oart-chat-dot {
    0%, 60%, 100% { opacity: .35; transform: translateY(0); }
    30% { opacity: 1; transform: translateY(calc(var(--oart-chat-typing-dot-size) * -.55)); }
}

/* Everything visible at once, and nothing moving. The widget also checks this
   in JS so the sequence never starts. */
@media (prefers-reduced-motion: reduce) {
    .oart-chat[data-reduced-motion="1"] .oart-chat__bubble {
        opacity: 1;
        transform: none;
        transition: none;
    }
    .oart-chat[data-reduced-motion="1"] .oart-chat__typing { display: none; }
}

/* ===================================================================
   Gradient line
   The two colour stops are worked out from a centre point and a softness, so
   the blend can be dragged anywhere along the line and tightened to a hard
   edge. Stops are clamped to 0-100% so an off-centre point with a wide
   softness cannot invert them.
   =================================================================== */

.oart-line {
    --oart-line-thickness: 2px;
    --oart-line-length: 100%;
    --oart-line-align: flex-start;
    --oart-line-radius: 0px;
    --oart-line-from: rgba(0, 0, 0, 0);
    --oart-line-to: #000;
    --oart-line-point: 50;
    --oart-line-soft: 100;

    /* stop positions, as plain numbers then clamped into a sane range */
    --oart-line-a: clamp(0%, calc((var(--oart-line-point) - var(--oart-line-soft) / 2) * 1%), 100%);
    --oart-line-b: clamp(0%, calc((var(--oart-line-point) + var(--oart-line-soft) / 2) * 1%), 100%);

    display: flex;
    width: 100%;
}

.oart-line__rule {
    display: block;
    border-radius: var(--oart-line-radius);
    background-image: linear-gradient(
        var(--oart-line-angle, 90deg),
        var(--oart-line-from) var(--oart-line-a),
        var(--oart-line-to) var(--oart-line-b)
    );
}

.oart-line--horizontal {
    justify-content: var(--oart-line-align);
}

.oart-line--horizontal .oart-line__rule {
    width: var(--oart-line-length);
    height: var(--oart-line-thickness);
    --oart-line-angle: 90deg;
}

.oart-line--vertical {
    align-items: var(--oart-line-align);
    justify-content: center;
}

.oart-line--vertical .oart-line__rule {
    width: var(--oart-line-thickness);
    height: var(--oart-line-length);
    --oart-line-angle: 180deg;
}

.oart-line--horizontal.oart-line--flip .oart-line__rule { --oart-line-angle: 270deg; }
.oart-line--vertical.oart-line--flip .oart-line__rule { --oart-line-angle: 0deg; }

/* ===================================================================
   CTA button
   Flat brand pill at rest with the round letter bubble popping up on hover.
   Point direction for both shapes is a control, so all four artwork variants
   are here - generated from the same two source paths by flipping inside the
   SVG rather than transforming the element (which would flip the text too).
   Pill masking follows the same three-piece rule as the menu and chat.
   =================================================================== */

.oart-cta {
    --oart-cta-align: flex-start;
    --oart-cta-h: 64px;
    --oart-cta-pl: 44px;
    --oart-cta-pr: 44px;
    --oart-cta-label-x: 0px;
    --oart-cta-label-y: 0px;
    --oart-cta-minw: 0px;
    --oart-cta-text: #FF6A63;
    --oart-cta-bg: #000;
    --oart-cta-speed: 260ms;
    --oart-cta-scale-hover: 1;
    --oart-cta-rotate-hover: 0deg;

    --oart-cta-bub-size: 96px;
    --oart-cta-bub-bg: #000;
    --oart-cta-bub-text: #EFE3ED;
    --oart-cta-bub-letter-x: 0px;
    --oart-cta-bub-letter-y: .14em;
    --oart-cta-bub-x: 42%;
    --oart-cta-bub-y: 8px;
    --oart-cta-bub-dur: 320ms;
    --oart-cta-bub-delay: 0ms;
    --oart-cta-bub-rise: 12px;
    --oart-cta-bub-from-scale: .6;
    --oart-cta-bub-from-rotate: -8deg;

    --oart-cta-pill-bl-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-cta-pill-bl-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-cta-pill-br-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oart-cta-pill-br-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oart-cta-pill-tl-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-pill-tl-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-pill-tr-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-pill-tr-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-mid-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' viewBox='40 0 20 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-cta-mid-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' viewBox='40 0 20 24.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-pill-none-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21.17'%3E%3Crect x='0' y='0' width='100.32' height='21.17' rx='10.585'/%3E%3C/svg%3E");
    --oart-cta-pill-none-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 21.17'%3E%3Crect x='0' y='0' width='100.32' height='21.17' rx='10.585'/%3E%3C/svg%3E");
    /* The stretched middle needs preserveAspectRatio='none' or the SVG fits
       its viewBox by height and centres it, painting a rounded end in the
       middle of the band with bare gaps either side. The pointed variants
       got this in 2.0.2; the no-point one reused its own left cap as the
       middle and so kept the bug. */
    --oart-cta-mid-none: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' viewBox='40 0 20 21.17'%3E%3Crect x='0' y='0' width='100.32' height='21.17' rx='10.585'/%3E%3C/svg%3E");
    --oart-cta-round-br: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/svg%3E");
    --oart-cta-round-bl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cg transform='translate(81.84 0) scale(-1 1)'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-round-tr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cg transform='translate(0 74.44) scale(1 -1)'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-cta-round-tl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cg transform='translate(81.84 0) scale(-1 1) translate(0 74.44) scale(1 -1)'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/g%3E%3C/svg%3E");

    display: flex;
    justify-content: var(--oart-cta-align);
}
.oart-cta__btn {
    --bm-h: var(--oart-cta-h);
    --bm-box: calc(var(--bm-h) * 1.1786);
    --bm-cap: calc(var(--bm-box) * 0.8818);
    --bm-mid: calc(var(--bm-box) * 0.75);
    /* How far the point's tip reaches PAST the pill body sideways. The
       artwork is 100.32 wide and the body's cap ends at 94.6, so 5.72 of
       24.95 vertical units. Measured on a real render at h=57: body ends
       at x=261, element at x=276, so 15px against 15.4 predicted.
       Without compensating for this the label centres on the element box
       instead of the pill, and sits half the overhang off-centre. */
    --bm-ox: calc(var(--bm-box) * 0.2293);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    height: var(--bm-box);
    min-width: max(var(--oart-cta-minw), calc(var(--bm-cap) * 2));
    padding: 0 var(--oart-cta-pr) 0 var(--oart-cta-pl);
    text-decoration: none;
    line-height: 1;
    color: var(--oart-cta-text);
    background-color: var(--oart-cta-bg);
    transition: background-color var(--oart-cta-speed) ease,
                color var(--oart-cta-speed) ease,
                transform var(--oart-cta-speed) ease;

    /* every layer from the same artwork at the same vertical scale, so the
       pieces meet without a step */
    -webkit-mask-image: var(--bm-cap-a), var(--bm-cap-b), var(--bm-cap-mid);
    mask-image: var(--bm-cap-a), var(--bm-cap-b), var(--bm-cap-mid);
    -webkit-mask-repeat: no-repeat, no-repeat, no-repeat;
    mask-repeat: no-repeat, no-repeat, no-repeat;
    -webkit-mask-size: auto 100%, auto 100%, calc(100% - var(--bm-mid) * 2) 100%;
    mask-size: auto 100%, auto 100%, calc(100% - var(--bm-mid) * 2) 100%;
}

/* points at the bottom: body sits at the top of the box, overhang below */
.oart-cta__btn--point-bl,
.oart-cta__btn--point-br {
    padding-bottom: calc(var(--bm-box) - var(--bm-h));
    -webkit-mask-position: left top, right top, var(--bm-mid) top;
    mask-position: left top, right top, var(--bm-mid) top;
}

/* points at the top: body sits at the bottom, overhang above */
.oart-cta__btn--point-tl,
.oart-cta__btn--point-tr {
    padding-top: calc(var(--bm-box) - var(--bm-h));
    -webkit-mask-position: left bottom, right bottom, var(--bm-mid) bottom;
    mask-position: left bottom, right bottom, var(--bm-mid) bottom;
}

/* The point eats into one side. Pad that side by the overhang so the
   content box is the PILL, not the element, and the label centres on the
   shape the eye actually sees. */
.oart-cta__btn--point-tr,
.oart-cta__btn--point-br {
    padding-right: calc(var(--oart-cta-pr) + var(--bm-ox));
}

.oart-cta__btn--point-tl,
.oart-cta__btn--point-bl {
    padding-left: calc(var(--oart-cta-pl) + var(--bm-ox));
}

.oart-cta__btn--point-bl { --bm-cap-a: var(--oart-cta-pill-bl-a); --bm-cap-b: var(--oart-cta-pill-bl-b); --bm-cap-mid: var(--oart-cta-mid-down); }
.oart-cta__btn--point-br { --bm-cap-a: var(--oart-cta-pill-br-a); --bm-cap-b: var(--oart-cta-pill-br-b); --bm-cap-mid: var(--oart-cta-mid-down); }
.oart-cta__btn--point-tl { --bm-cap-a: var(--oart-cta-pill-tl-a); --bm-cap-b: var(--oart-cta-pill-tl-b); --bm-cap-mid: var(--oart-cta-mid-up); }
.oart-cta__btn--point-tr { --bm-cap-a: var(--oart-cta-pill-tr-a); --bm-cap-b: var(--oart-cta-pill-tr-b); --bm-cap-mid: var(--oart-cta-mid-up); }

/* no point: plain stadium, no overhang to leave room for */
.oart-cta__btn--point-none {
    --bm-cap-a: var(--oart-cta-pill-none-a);
    --bm-cap-b: var(--oart-cta-pill-none-b);
    --bm-cap-mid: var(--oart-cta-mid-none);
    --bm-box: var(--bm-h);
    --bm-ox: 0px;
    -webkit-mask-position: left top, right top, var(--bm-mid) top;
    mask-position: left top, right top, var(--bm-mid) top;
}

.oart-cta__btn:hover,
.oart-cta__btn:focus-visible {
    background-color: var(--oart-cta-bg-hover, var(--oart-cta-bg));
    color: var(--oart-cta-text-hover, var(--oart-cta-text));
    transform: scale(var(--oart-cta-scale-hover)) rotate(var(--oart-cta-rotate-hover));
}

/* The nudge is a transform, not padding, for two reasons: padding cannot go
   negative, so a padding control can only ever push the type one way; and a
   transform moves the type without touching the box the sliced mask is
   measured against. */
.oart-cta__label {
    position: relative;
    transform: translate(var(--oart-cta-label-x), var(--oart-cta-label-y));
}

/* --- the round bubble that pops up on hover --- */
/* The button carries a mask, and a mask clips every descendant - a bubble
   inside it would be cut away entirely, because it sits outside the pill
   shape. So the bubble is a sibling, and hover is read off the button. */
.oart-cta__inner {
    position: relative;
    display: inline-block;
}

.oart-cta__bubble {
    position: absolute;
    bottom: calc(100% + var(--oart-cta-bub-y));
    left: var(--oart-cta-bub-x);
    display: grid;
    place-items: center;
    width: var(--oart-cta-bub-size);
    aspect-ratio: 81.84 / 74.44;
    background-color: var(--oart-cta-bub-bg);
    pointer-events: none;

    opacity: 0;
    transform: translateY(var(--oart-cta-bub-rise))
               scale(var(--oart-cta-bub-from-scale))
               rotate(var(--oart-cta-bub-from-rotate));
    transform-origin: center bottom;
    transition: opacity var(--oart-cta-bub-dur) ease var(--oart-cta-bub-delay),
                transform var(--oart-cta-bub-dur) cubic-bezier(.22, 1.5, .36, 1) var(--oart-cta-bub-delay);
}

.oart-cta__bubble--point-br { -webkit-mask: var(--oart-cta-round-br) center / contain no-repeat; mask: var(--oart-cta-round-br) center / contain no-repeat; }
.oart-cta__bubble--point-bl { -webkit-mask: var(--oart-cta-round-bl) center / contain no-repeat; mask: var(--oart-cta-round-bl) center / contain no-repeat; }
.oart-cta__bubble--point-tr { -webkit-mask: var(--oart-cta-round-tr) center / contain no-repeat; mask: var(--oart-cta-round-tr) center / contain no-repeat; }
.oart-cta__bubble--point-tl { -webkit-mask: var(--oart-cta-round-tl) center / contain no-repeat; mask: var(--oart-cta-round-tl) center / contain no-repeat; }

.oart-cta__btn:hover ~ .oart-cta__bubble,
.oart-cta__btn:focus-visible ~ .oart-cta__bubble {
    opacity: 1;
    transform: none;
}

.oart-cta__bubble-text {
    color: var(--oart-cta-bub-text);
    line-height: 1;
    transform: translate(var(--oart-cta-bub-letter-x), var(--oart-cta-bub-letter-y));
}

/* Same reasoning as the menu: the button's transition and the letter bubble
   popping up only happen on hover, so they no longer switch themselves off on
   a device asking to limit animation. */

/* =====================================================================
   Conversation Bubble (oart-conversation-bubble)
   A speech bubble whose outline draws itself on, then plays a four-beat
   loop inside: a cold network warms up, a chat exchange, a facial-scan,
   and a closing heart. Every colour, the size, the speed and the outline
   are CSS variables driven by Style controls. pathLength is set as an SVG
   attribute in the markup, never here: it is not a CSS property, and a bare
   stroke-dasharray:1 without it would render the outline as dots.
   ===================================================================== */
.ocb-wrap {
    display: flex;
    width: 100%;
    justify-content: center;
}

.ocb {
    --ocb-size: 460px;
    --ocb-outline: #17141D;
    --ocb-outline-w: 3;
    --ocb-dot-cold: rgba(255, 255, 255, .62);
    --ocb-dot-warm: #FFA63A;
    --ocb-line: rgba(255, 255, 255, .45);
    --ocb-line-warm: #FFA63A;
    --ocb-chat-bg: #FFFFFF;
    --ocb-chat-text: #2A2340;
    --ocb-tick: #2EA6FF;
    --ocb-tick-off: #C3BDD0;
    --ocb-heart: #FF76BC;
    --ocb-reticle: #FFA63A;
    --ocb-scan: #FFE08A;
    --ocb-face: #FFFFFF;
    --ocb-verify: #33D17A;
    --ocb-spark: #FFFFFF;
    --ocb-cycle: 13s;

    position: relative;
    width: var(--ocb-size);
    max-width: 100%;
    aspect-ratio: 1 / 1;
}

.ocb__frame {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/* Static by default. The draw-on is opt-in (.ocb--draw) and gated on the
   bubble scrolling into view, added by JS as .ocb--inview. */
.ocb__outline {
    fill: none;
    stroke: var(--ocb-outline);
    stroke-width: var(--ocb-outline-w);
    stroke-linecap: round;
    stroke-linejoin: round;
}

.ocb--draw.ocb--js .ocb__outline {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
}

.ocb--draw.ocb--js.ocb--inview .ocb__outline {
    animation: ocb-draw 1.6s cubic-bezier(.65, 0, .35, 1) .1s forwards;
}

/* No JS at all: draw once on load so nothing depends on the observer. */
.ocb--draw:not(.ocb--js) .ocb__outline {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: ocb-draw 1.6s cubic-bezier(.65, 0, .35, 1) .3s forwards;
}

@keyframes ocb-draw {
    to { stroke-dashoffset: 0; }
}

/* Matched to the drawn bubble's real circle: centre (51.1, 46.9), r 43 in
   the frame's 0..100 viewBox, so the interior sits dead-centre in it. */
.ocb__stage {
    position: absolute;
    left: 8.1%;
    top: 3.9%;
    width: 86%;
    height: 86%;
    border-radius: 50%;
    overflow: hidden;
}

/* The interior loop holds paused until the bubble is scrolled into view, so
   it always starts from the first beat. With no JS it simply runs. */
.ocb--js .ocb__stage * {
    animation-play-state: paused;
}

.ocb--js.ocb--inview .ocb__stage * {
    animation-play-state: running;
}

/* ---- beats 1 + 2: the network ---- */
.ocb__net {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.ocb__net line {
    stroke: var(--ocb-line);
    stroke-width: 1.1;
    stroke-linecap: round;
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: ocb-line var(--ocb-cycle) linear infinite;
}

.ocb__net line:nth-child(2) { animation-delay: -.25s; }
.ocb__net line:nth-child(3) { animation-delay: -.5s; }
.ocb__net line:nth-child(4) { animation-delay: -.35s; }
.ocb__net line:nth-child(5) { animation-delay: -.6s; }
.ocb__net line:nth-child(6) { animation-delay: -.15s; }

@keyframes ocb-line {
    0%, 5%  { stroke-dashoffset: 1; opacity: 0; stroke: var(--ocb-line); }
    7%      { opacity: 1; }
    18%     { stroke-dashoffset: 0; stroke: var(--ocb-line); }
    26%     { stroke-dashoffset: 0; stroke: var(--ocb-line-warm); opacity: 1; }
    32%     { opacity: 1; stroke: var(--ocb-line-warm); }
    37%     { opacity: 0; }
    100%    { opacity: 0; stroke-dashoffset: 0; }
}

.ocb__dot {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: 12px;
    height: 12px;
    margin: -6px 0 0 -6px;
    border-radius: 50%;
    background: var(--ocb-dot-cold);
    animation: ocb-dot var(--ocb-cycle) linear infinite;
}

.ocb__dot:nth-child(2) { animation-delay: -.15s; }
.ocb__dot:nth-child(3) { animation-delay: -.3s; }
.ocb__dot:nth-child(4) { animation-delay: -.1s; }
.ocb__dot:nth-child(5) { animation-delay: -.4s; }
.ocb__dot:nth-child(6) { animation-delay: -.25s; }

@keyframes ocb-dot {
    0%, 2% { opacity: 0; transform: scale(.3); background: var(--ocb-dot-cold); }
    6%     { opacity: 1; transform: scale(1); background: var(--ocb-dot-cold); }
    16%    { background: var(--ocb-dot-cold); }
    20%    { background: var(--ocb-dot-warm); }
    32%    { opacity: 1; transform: scale(1); background: var(--ocb-dot-warm); }
    37%    { opacity: 0; transform: scale(.6); }
    100%   { opacity: 0; }
}

.ocb__ring {
    position: absolute;
    inset: -7px;
    border-radius: 50%;
    border: 2px solid var(--ocb-dot-warm);
    opacity: 0;
    animation: ocb-ring var(--ocb-cycle) ease-out infinite;
}

.ocb__dot:nth-child(2) .ocb__ring { animation-delay: 0s; }
.ocb__dot:nth-child(4) .ocb__ring { animation-delay: -.4s; }
.ocb__dot:nth-child(6) .ocb__ring { animation-delay: -.8s; }

@keyframes ocb-ring {
    0%, 18% { opacity: 0; transform: scale(.4); }
    22%     { opacity: .85; transform: scale(.55); }
    32%     { opacity: 0; transform: scale(2.6); }
    100%    { opacity: 0; }
}

/* ---- beat 3: the conversation ---- */
.ocb__chat {
    position: absolute;
    left: var(--x);
    top: var(--y);
    transform: translate(-50%, -50%);
    background: var(--ocb-chat-bg);
    color: var(--ocb-chat-text);
    font-size: 15px;
    font-weight: 600;
    padding: 10px 14px;
    border-radius: 16px;
    white-space: nowrap;
    box-shadow: 0 8px 20px rgba(30, 10, 40, .18);
    opacity: 0;
}

.ocb__chat--in { border-bottom-left-radius: 5px; }
.ocb__chat--out { border-bottom-right-radius: 5px; }

.ocb__tick {
    color: var(--ocb-tick-off);
    font-weight: 800;
    margin-left: 4px;
    letter-spacing: -3px;
}

.ocb__typing { animation: ocb-typing var(--ocb-cycle) linear infinite; }

.ocb__typing i {
    display: inline-block;
    width: 7px;
    height: 7px;
    margin: 0 2px;
    border-radius: 50%;
    background: #B7B1C6;
    animation: ocb-typedot 1s ease-in-out infinite;
}

.ocb__typing i:nth-child(2) { animation-delay: .16s; }
.ocb__typing i:nth-child(3) { animation-delay: .32s; }

@keyframes ocb-typedot {
    0%, 100% { transform: translateY(0); opacity: .5; }
    50%      { transform: translateY(-4px); opacity: 1; }
}

.ocb__chat--1 { animation: ocb-chat1 var(--ocb-cycle) linear infinite; }
.ocb__chat--2 { animation: ocb-chat2 var(--ocb-cycle) linear infinite; }
.ocb__chat--1 .ocb__tick { animation: ocb-tick var(--ocb-cycle) linear infinite; }

@keyframes ocb-typing {
    0%, 62% { opacity: 0; transform: translate(-50%, -50%) translateY(6px); }
    66%     { opacity: 1; transform: translate(-50%, -50%) translateY(0); }
    70%     { opacity: 1; }
    73%     { opacity: 0; }
    100%    { opacity: 0; }
}

@keyframes ocb-chat1 {
    0%, 71% { opacity: 0; transform: translate(-50%, -50%) translateY(10px) scale(.85); }
    75%     { opacity: 1; transform: translate(-50%, -50%) translateY(0) scale(1); }
    84%     { opacity: 1; }
    88%     { opacity: 0; }
    100%    { opacity: 0; }
}

@keyframes ocb-chat2 {
    0%, 77% { opacity: 0; transform: translate(-50%, -50%) translateY(10px) scale(.85); }
    81%     { opacity: 1; transform: translate(-50%, -50%) translateY(0) scale(1); }
    85%     { opacity: 1; }
    88%     { opacity: 0; }
    100%    { opacity: 0; }
}

@keyframes ocb-tick {
    0%, 81% { color: var(--ocb-tick-off); }
    85%     { color: var(--ocb-tick); }
    88%     { color: var(--ocb-tick); }
    100%    { color: var(--ocb-tick-off); }
}

/* ---- beat 4: the smart-tech scan ---- */
.ocb__reticle {
    position: absolute;
    left: 50%;
    top: 48%;
    width: 46%;
    height: 52%;
    transform: translate(-50%, -50%);
    opacity: 0;
    animation: ocb-reticle var(--ocb-cycle) cubic-bezier(.22, 1, .36, 1) infinite;
}

.ocb__bracket {
    position: absolute;
    width: 26px;
    height: 26px;
    border: 3px solid var(--ocb-reticle);
    border-radius: 3px;
}

.ocb__bracket--tl { top: 0; left: 0; border-right: 0; border-bottom: 0; border-top-left-radius: 8px; }
.ocb__bracket--tr { top: 0; right: 0; border-left: 0; border-bottom: 0; border-top-right-radius: 8px; }
.ocb__bracket--bl { bottom: 0; left: 0; border-right: 0; border-top: 0; border-bottom-left-radius: 8px; }
.ocb__bracket--br { bottom: 0; right: 0; border-left: 0; border-top: 0; border-bottom-right-radius: 8px; }

.ocb__scan {
    position: absolute;
    left: 6%;
    right: 6%;
    height: 3px;
    top: 4%;
    background: var(--ocb-scan);
    border-radius: 3px;
    box-shadow: 0 0 12px 1px var(--ocb-scan);
    opacity: 0;
    animation: ocb-scan var(--ocb-cycle) ease-in-out infinite;
}

@keyframes ocb-reticle {
    0%, 38% { opacity: 0; transform: translate(-50%, -50%) scale(1.3); }
    43%     { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    60%     { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    64%     { opacity: 0; transform: translate(-50%, -50%) scale(1); }
    100%    { opacity: 0; }
}

@keyframes ocb-scan {
    0%, 42% { opacity: 0; top: 4%; }
    45%     { opacity: 1; top: 4%; }
    57%     { opacity: 1; top: 94%; }
    60%     { opacity: 0; top: 94%; }
    100%    { opacity: 0; }
}

.ocb__face {
    position: absolute;
    left: 50%;
    top: 47%;
    width: 32%;
    height: 32%;
    transform: translate(-50%, -50%);
    fill: var(--ocb-face);
    opacity: 0;
    animation: ocb-face var(--ocb-cycle) cubic-bezier(.22, 1, .36, 1) infinite;
}

@keyframes ocb-face {
    0%, 39% { opacity: 0; transform: translate(-50%, -50%) scale(.8); }
    44%     { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    60%     { opacity: 1; }
    64%     { opacity: 0; }
    100%    { opacity: 0; }
}

.ocb__verify {
    position: absolute;
    left: 71%;
    top: 72%;
    width: 28px;
    height: 28px;
    margin: -14px 0 0 -14px;
    border-radius: 50%;
    background: var(--ocb-verify);
    color: #FFFFFF;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 800;
    box-shadow: 0 4px 12px rgba(20, 40, 20, .3);
    opacity: 0;
    animation: ocb-verify var(--ocb-cycle) cubic-bezier(.34, 1.56, .64, 1) infinite;
}

@keyframes ocb-verify {
    0%, 56% { opacity: 0; transform: scale(.2); }
    60%     { opacity: 1; transform: scale(1.15); }
    62%     { transform: scale(1); }
    64%     { opacity: 1; transform: scale(1); }
    68%     { opacity: 0; }
    100%    { opacity: 0; }
}

.ocb__spark {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;
    background: var(--ocb-spark);
    clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
    opacity: 0;
    animation: ocb-spark var(--ocb-cycle) ease-in-out infinite;
}

.ocb__spark:nth-of-type(2) { animation-delay: -.5s; width: 12px; height: 12px; }
.ocb__spark:nth-of-type(3) { animation-delay: -.9s; width: 20px; height: 20px; }

@keyframes ocb-spark {
    0%, 42% { opacity: 0; transform: scale(0) rotate(0deg); }
    48%     { opacity: 1; transform: scale(1) rotate(25deg); }
    54%     { opacity: .35; transform: scale(.7) rotate(0deg); }
    60%     { opacity: 1; transform: scale(1.1) rotate(-18deg); }
    64%     { opacity: 0; transform: scale(0) rotate(0deg); }
    100%    { opacity: 0; }
}

/* ---- closing note: the human touch ---- */
.ocb__heart {
    position: absolute;
    left: 54%;
    top: 56%;
    font-size: 26px;
    color: var(--ocb-heart);
    transform: translate(-50%, 0);
    opacity: 0;
    animation: ocb-heart var(--ocb-cycle) ease-out infinite;
}

@keyframes ocb-heart {
    0%, 88% { opacity: 0; transform: translate(-50%, 0) scale(.3); }
    92%     { opacity: 1; transform: translate(-50%, -14px) scale(1); }
    97%     { opacity: 0; transform: translate(-50%, -52px) scale(1.15); }
    100%    { opacity: 0; }
}

/* ===================================================================
   Team bubble
   Artwork from Brand/team widget, used as masks so every colour stays a
   control.

   The photo bubble has a fixed aspect ratio, so masking the artwork whole
   is exact. Its ring and its photo are two concentric masks off the same
   centre: ring box 81.84 x 74.44, photo box 71.83 x 64.93, which leaves an
   even 4.25 units of ring the whole way round including the tail.

   The name pill has to stretch to whatever the name is, so it follows the
   same three-piece rule as the menu and the CTA: both caps keep their real
   geometry (one carries the point) and only the straight middle stretches.
   Artwork is 100.32 x 24.95 with a 21.17 tall body, so the full box is the
   pill height x 1.1786 and each cap slice is 22/24.95 of the box height.

   The panel is a SIBLING of the photo, never a child. A mask clips every
   descendant, so a panel inside the masked bubble is erased at paint and
   every measurement still reads correct.
   =================================================================== */

.oart-team {
    /* photo bubble: fixed aspect, so the artwork masks whole and is exact */
    --oart-team-ring-tl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M41.67,1.01c22.17,0,40.17,14.36,40.17,36.71,0,22.36-17.99,36.71-40.17,36.71-22.17,0-40.17-14.54-40.17-36.71,0-8.41,2.59-15.72,7.01-21.55L0,0l19.44,6.65c6.37-3.64,14.01-5.64,22.23-5.64Z'/%3E%3C/svg%3E");
    --oart-team-ring-tr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M40.17,1.01C17.99,1.01,0,15.37,0,37.72c0,22.36,17.99,36.71,40.17,36.71,22.17,0,40.17-14.54,40.17-36.71,0-8.41-2.59-15.72-7.01-21.55L81.84,0l-19.44,6.65c-6.37-3.64-14.01-5.64-22.23-5.64Z'/%3E%3C/svg%3E");
    --oart-team-ring-bl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M41.67,73.43c22.17,0,40.17-14.36,40.17-36.71C81.84,14.36,63.84,0,41.67,0,19.49,0,1.5,14.54,1.5,36.71c0,8.41,2.59,15.72,7.01,21.55L0,74.44l19.44-6.65c6.37,3.64,14.01,5.64,22.23,5.64Z'/%3E%3C/svg%3E");
    --oart-team-ring-br: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 81.84 74.44'%3E%3Cpath d='M40.17,73.43c-22.17,0-40.17-14.36-40.17-36.71C0,14.36,17.99,0,40.17,0c22.17,0,40.17,14.54,40.17,36.71,0,8.41-2.59,15.72-7.01,21.55l8.51,16.17-19.44-6.65c-6.37,3.64-14.01,5.64-22.23,5.64Z'/%3E%3C/svg%3E");

    /* the photo's own mask, concentric inside the ring */
    --oart-team-pic-tl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 71.83 64.93'%3E%3Cpath d='M35.92,64.93C15.1,64.93,0,51.27,0,32.46c0-7.11,2.13-13.67,6.15-18.99l1.63-2.16L3,2.23l11.14,3.81,1.67-.96C21.61,1.76,28.57,0,35.92,0c20.81,0,35.92,13.65,35.92,32.46s-15.11,32.46-35.92,32.46Z'/%3E%3C/svg%3E");
    --oart-team-pic-tr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 71.83 64.93'%3E%3Cpath d='M35.92,64.93C15.1,64.93,0,51.27,0,32.46S15.1,0,35.92,0c7.35,0,14.3,1.76,20.12,5.08l1.67.96,11.14-3.81-4.79,9.09,1.63,2.16c4.02,5.31,6.15,11.88,6.15,18.99,0,18.81-15.1,32.46-35.92,32.46Z'/%3E%3C/svg%3E");
    --oart-team-pic-bl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 71.83 64.93'%3E%3Cpath d='M35.92,64.93c20.81,0,35.92-13.65,35.92-32.46S56.73,0,35.92,0,0,13.65,0,32.46c0,7.11,2.13,13.67,6.15,18.99l1.63,2.16-4.79,9.09,11.14-3.81,1.67.96c5.81,3.33,12.77,5.08,20.11,5.08Z'/%3E%3C/svg%3E");
    --oart-team-pic-br: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 71.83 64.93'%3E%3Cpath d='M35.92,64.93C15.11,64.93,0,51.27,0,32.46S15.11,0,35.92,0s35.92,13.65,35.92,32.46c0,7.11-2.13,13.67-6.15,18.99l-1.63,2.16,4.79,9.09-11.14-3.81-1.67.96c-5.81,3.33-12.77,5.08-20.11,5.08Z'/%3E%3C/svg%3E");

    /* the point on its own, lifted from the chat bubble: the pill body is a
       plain stadium, so only the point has to be artwork */
    --oart-pt-bl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 6 18 18.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oart-pt-br: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='82.32 6 18 18.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oart-pt-tl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/g%3E%3C/svg%3E");
    --oart-pt-tr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='82.32 0 18 18.95'%3E%3Cg transform='translate(0 24.95) scale(1 -1)'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/g%3E%3C/svg%3E");

    /* --- the name bubble's point ---
       The corner is chosen by CSS variable rather than a class PHP prints, so
       the control can be responsive. Each corner publishes a complete set here
       (artwork, which edge it hangs off, which end it slides from) and a single
       {{VALUE}} picks one set. These have to live on the root, not on the pill,
       because a var() inside a custom property resolves on the element that
       declares it, and that is where the control writes. */
    --tm-pt-w: calc(var(--oart-team-pill-h) * 0.8503 * var(--oart-team-pt-size, 1));
    --tm-pt-h: calc(var(--oart-team-pill-h) * 0.8951 * var(--oart-team-pt-size, 1));
    /* 0 parks the point at the end it naturally comes from, 100 sends it to the
       far end, so the slider reads the same for all four directions. */
    --tm-pt-slide: calc((100% - var(--tm-pt-w)) * var(--oart-team-pt-x, 0) / 100);
    /* The crop carries 80.05% body and 19.95% overhang, so this much of the
       point sits inside the pill and the rest pokes out. Capped at the pill's
       own height, or the buried part clears the far edge and the point reads as
       a black rectangle stuck to the bubble. */
    --tm-pt-in: min(calc(var(--tm-pt-h) * 0.8005), 100%);

    --oart-team-ptset-tl-art: var(--oart-pt-tl);
    --oart-team-ptset-tl-top: auto;
    --oart-team-ptset-tl-bottom: calc(100% - var(--tm-pt-in));
    --oart-team-ptset-tl-left: var(--tm-pt-slide);
    --oart-team-ptset-tl-right: auto;
    --oart-team-ptset-tl-show: 1;
    --oart-team-ptset-tr-art: var(--oart-pt-tr);
    --oart-team-ptset-tr-top: auto;
    --oart-team-ptset-tr-bottom: calc(100% - var(--tm-pt-in));
    --oart-team-ptset-tr-left: auto;
    --oart-team-ptset-tr-right: var(--tm-pt-slide);
    --oart-team-ptset-tr-show: 1;
    --oart-team-ptset-bl-art: var(--oart-pt-bl);
    --oart-team-ptset-bl-top: calc(100% - var(--tm-pt-in));
    --oart-team-ptset-bl-bottom: auto;
    --oart-team-ptset-bl-left: var(--tm-pt-slide);
    --oart-team-ptset-bl-right: auto;
    --oart-team-ptset-bl-show: 1;
    --oart-team-ptset-br-art: var(--oart-pt-br);
    --oart-team-ptset-br-top: calc(100% - var(--tm-pt-in));
    --oart-team-ptset-br-bottom: auto;
    --oart-team-ptset-br-left: auto;
    --oart-team-ptset-br-right: var(--tm-pt-slide);
    --oart-team-ptset-br-show: 1;
    --oart-team-ptset-none-art: var(--oart-pt-br);
    --oart-team-ptset-none-top: auto;
    --oart-team-ptset-none-bottom: auto;
    --oart-team-ptset-none-left: auto;
    --oart-team-ptset-none-right: auto;
    --oart-team-ptset-none-show: 0;

    /* per-corner photo offsets, selected by the responsive Tail control */
    --oart-team-pic-x-tl: 7.026%;  --oart-team-pic-y-tl: 7.066%;
    --oart-team-pic-x-tr: 5.193%;  --oart-team-pic-y-tr: 7.066%;
    --oart-team-pic-x-bl: 7.026%;  --oart-team-pic-y-bl: 5.716%;
    --oart-team-pic-x-br: 5.193%;  --oart-team-pic-y-br: 5.716%;

    /* fallback if no generated CSS has landed yet */
    --oart-team-ring-art: var(--oart-team-ring-br);
    --oart-team-pic-art: var(--oart-team-pic-br);
    --oart-team-pic-x: var(--oart-team-pic-x-br);
    --oart-team-pic-y: var(--oart-team-pic-y-br);

    --oart-team-photo-w: 260px;
    --oart-team-ring: #FF6A63;
    --oart-team-pill: #000;
    --oart-team-pill-text: #fff;
    --oart-team-pill-h: 34px;
    --oart-team-pill-px: 22px;
    --oart-team-sheet-bg: #F3E8F1;
    --oart-team-sheet-text: #2B2B2B;
    --oart-team-sheet-pad: 16px;
    --oart-team-sheet-radius: 4px;
    --oart-team-panel-w: 250px;
    --oart-team-panel-x: 0px;
    --oart-team-panel-y: 0px;
    --oart-team-gap: 10px;
    --oart-team-speed: 420ms;
    --oart-team-hover-scale: 1.04;
    --oart-team-hover-lift: -6px;
    --oart-team-hover-rotate: 0deg;
    --oart-team-ease: cubic-bezier(.22, 1, .36, 1);

    position: relative;
    display: block;
}

.oart-team__stage {
    position: relative;
    width: var(--oart-team-photo-w);
    max-width: 100%;
}

/* --- the photo bubble --- */
.oart-team__photo {
    position: relative;
    display: block;
    width: 100%;
    /* the artwork's own ratio, so `contain` fills the box exactly and the
       concentric percentages below stay true */
    aspect-ratio: 81.84 / 74.44;
    background-color: var(--oart-team-ring);
    -webkit-mask: var(--oart-team-ring-art) center / contain no-repeat;
    mask: var(--oart-team-ring-art) center / contain no-repeat;
    transition: transform var(--oart-team-speed) var(--oart-team-ease);
    will-change: transform;
}

.oart-team__photo-img {
    position: absolute;
    display: block;
    width: 87.769%;
    height: 87.225%;
    left: var(--oart-team-pic-x);
    top: var(--oart-team-pic-y);
    background-color: rgba(0, 0, 0, .06);
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    -webkit-mask: var(--oart-team-pic-art) center / contain no-repeat;
    mask: var(--oart-team-pic-art) center / contain no-repeat;
}

/* The tail corner is chosen by CSS variable, not by a class PHP prints, so the
   control can be responsive: PHP renders one markup for every breakpoint and
   Elementor's own media queries swap these four values. Each corner's photo
   offset is published as its own pair so a single {{VALUE}} can select all
   four properties at once. */


/* --- the panel: name pill plus roll-out sheet --- */
.oart-team__panel {
    position: absolute;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: var(--oart-team-panel-align, flex-start);
    width: var(--oart-team-panel-w);
    max-width: none;
    gap: var(--oart-team-gap);
    transform: translate(var(--oart-team-panel-x), var(--oart-team-panel-y));
}

/* Anchored by the edge the sheet grows AWAY from, so the name pill never
   moves when the sheet rolls out. */
.oart-team--title-tl .oart-team__panel { top: -29%; right: 88%; }
.oart-team--title-tr .oart-team__panel { top: -29%; left: 88%; }
.oart-team--title-bl .oart-team__panel { bottom: -29%; right: 88%; flex-direction: column-reverse; }
.oart-team--title-br .oart-team__panel { bottom: -29%; left: 88%; flex-direction: column-reverse; }

.oart-team--title-tr,
.oart-team--title-br { --oart-team-panel-align: flex-end; }

/* --- the name pill ---
   The artwork's body is a stadium: its cap radius is exactly half its height,
   which CSS reproduces exactly at any width, so only the point needs to be
   artwork. That also frees the point from the pill's ends, so it can be
   aimed at any corner and slid anywhere along the edge.

   The earlier version masked the whole pill in three slices. That welded the
   point to whichever end carried it, and only held for a single line. */
.oart-team__title {
    position: relative;
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    min-height: var(--oart-team-pill-h);
    max-width: 100%;
    padding: calc(var(--oart-team-pill-h) * .16) var(--oart-team-pill-px);
    border-radius: calc(var(--oart-team-pill-h) / 2);
    line-height: 1.15;
    color: var(--oart-team-pill-text);
    text-decoration: none;
    background-color: var(--oart-team-pill);
    /* guarantees a stacking context so the point below can sit at z-index -1,
       painting above this background but behind the name */
    isolation: isolate;
    /* slid with a transform, not a margin, so the bubble can travel anywhere
       including past the edge of the panel without disturbing the sheet */
    transform: translate(var(--oart-team-title-x, 0px), var(--oart-team-title-y, 0px));
    transition: transform var(--oart-team-speed) var(--oart-team-ease);
}

.oart-team__title::before {
    content: "";
    position: absolute;
    /* an absolutely positioned pseudo-element paints ABOVE in-flow text, so
       without this the point covers whichever letters it overlaps */
    z-index: -1;
    /* "no point" is the same set at zero size, which keeps every option
       reachable through the one {{VALUE}} the control substitutes */
    width: calc(var(--tm-pt-w) * var(--oart-team-pt-show, 1));
    height: calc(var(--tm-pt-h) * var(--oart-team-pt-show, 1));
    top: var(--oart-team-pt-top, auto);
    bottom: var(--oart-team-pt-bottom, auto);
    left: var(--oart-team-pt-left, auto);
    right: var(--oart-team-pt-right, auto);
    /* inherited, so the point can never drift from the bubble's own colour */
    background-color: inherit;
    -webkit-mask: var(--oart-team-pt-art) center / contain no-repeat;
    mask: var(--oart-team-pt-art) center / contain no-repeat;
}

/* Automatic: PHP works the corner out from the name position (which is not
   itself responsive) and prints one of these, which simply aliases the "auto"
   set onto that corner's set. */
.oart-team--pt-auto-tl { --oart-team-ptset-auto-art: var(--oart-team-ptset-tl-art); --oart-team-ptset-auto-top: var(--oart-team-ptset-tl-top); --oart-team-ptset-auto-bottom: var(--oart-team-ptset-tl-bottom); --oart-team-ptset-auto-left: var(--oart-team-ptset-tl-left); --oart-team-ptset-auto-right: var(--oart-team-ptset-tl-right); --oart-team-ptset-auto-show: var(--oart-team-ptset-tl-show); }
.oart-team--pt-auto-tr { --oart-team-ptset-auto-art: var(--oart-team-ptset-tr-art); --oart-team-ptset-auto-top: var(--oart-team-ptset-tr-top); --oart-team-ptset-auto-bottom: var(--oart-team-ptset-tr-bottom); --oart-team-ptset-auto-left: var(--oart-team-ptset-tr-left); --oart-team-ptset-auto-right: var(--oart-team-ptset-tr-right); --oart-team-ptset-auto-show: var(--oart-team-ptset-tr-show); }
.oart-team--pt-auto-bl { --oart-team-ptset-auto-art: var(--oart-team-ptset-bl-art); --oart-team-ptset-auto-top: var(--oart-team-ptset-bl-top); --oart-team-ptset-auto-bottom: var(--oart-team-ptset-bl-bottom); --oart-team-ptset-auto-left: var(--oart-team-ptset-bl-left); --oart-team-ptset-auto-right: var(--oart-team-ptset-bl-right); --oart-team-ptset-auto-show: var(--oart-team-ptset-bl-show); }
.oart-team--pt-auto-br { --oart-team-ptset-auto-art: var(--oart-team-ptset-br-art); --oart-team-ptset-auto-top: var(--oart-team-ptset-br-top); --oart-team-ptset-auto-bottom: var(--oart-team-ptset-br-bottom); --oart-team-ptset-auto-left: var(--oart-team-ptset-br-left); --oart-team-ptset-auto-right: var(--oart-team-ptset-br-right); --oart-team-ptset-auto-show: var(--oart-team-ptset-br-show); }

.oart-team__title-text {
    overflow: hidden;
    text-overflow: ellipsis;
    /* A capital does not sit centred in its own line box, so a perfectly
       centred box can still leave the name riding high. Nudged with a
       transform, not padding, because padding cannot go negative and the
       right value differs per font. */
    transform: translateY(var(--oart-team-name-y, 0px));
}

/* --- the roll-out sheet --- */
/* 0fr to 1fr reveals the sheet at its natural height without squashing the
   text, which a scaleY would do, and without hard-coding a height. */
.oart-team__sheet {
    display: grid;
    grid-template-rows: 0fr;
    width: 100%;
    /* slid with a transform, like the name bubble, so the sheet can travel on
       its own without changing the gap the layout has reserved for it */
    transform: translate(var(--oart-team-sheet-x, 0px), var(--oart-team-sheet-y, 0px));
    transition: grid-template-rows var(--oart-team-speed) var(--oart-team-ease),
                opacity var(--oart-team-speed) var(--oart-team-ease);
    opacity: 0;
}

.oart-team__sheet-clip {
    overflow: hidden;
    min-height: 0;
}

.oart-team__sheet-body {
    position: relative;
    padding: var(--oart-team-sheet-pad);
    border-radius: var(--oart-team-sheet-radius);
    background-color: var(--oart-team-sheet-bg);
    color: var(--oart-team-sheet-text);
}

.oart-team__sheet-body > *:first-child { margin-top: 0; }
.oart-team__sheet-body > *:last-child { margin-bottom: 0; }

/* The ghost holds the full text so the panel never changes size while the
   typewriter runs; the live copy is painted over it. */
.oart-team__sheet-ghost { visibility: hidden; }

.oart-team__sheet-live {
    position: absolute;
    inset: var(--oart-team-sheet-pad);
}

.oart-team__caret {
    display: inline-block;
    width: .08em;
    margin-left: .06em;
    background-color: currentColor;
    animation: oart-team-caret 900ms steps(2, start) infinite;
    /* sits on the text baseline and takes the line's height */
    vertical-align: -.12em;
    height: 1em;
}

.oart-team--typed-done .oart-team__caret { display: none; }

@keyframes oart-team-caret {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

/* --- hover / focus / tap open --- */
.oart-team:hover .oart-team__sheet,
.oart-team:focus-within .oart-team__sheet,
.oart-team.is-open .oart-team__sheet {
    grid-template-rows: 1fr;
    opacity: 1;
}

.oart-team:hover .oart-team__photo,
.oart-team:focus-within .oart-team__photo,
.oart-team.is-open .oart-team__photo {
    transform: translateY(var(--oart-team-hover-lift)) scale(var(--oart-team-hover-scale)) rotate(var(--oart-team-hover-rotate));
}

/* carries the slide through, or hovering would snap the pill back to zero */
.oart-team:hover .oart-team__title,
.oart-team:focus-within .oart-team__title,
.oart-team.is-open .oart-team__title {
    transform: translate(var(--oart-team-title-x, 0px), calc(var(--oart-team-title-y, 0px) + var(--oart-team-hover-lift) * .5));
}

.oart-team__trigger {
    display: block;
    cursor: pointer;
}

/* Held still in the editor: the panel is absolutely positioned and would
   otherwise sit collapsed and unreachable while styling it. */
body.elementor-editor-active .oart-team--editor-open .oart-team__sheet {
    grid-template-rows: 1fr;
    opacity: 1;
}

/* ===================================================================
   Chat form
   Carries the .oart-chat class too, so every bubble, point, side and
   typing style above applies unchanged and a form placed next to a chat
   reads as the same component. Only what a chat has no equivalent for
   lives here: the field someone types into, the send button, and the
   states in between.
   =================================================================== */

.oart-cf {
    --oart-cf-answer-w: 62%;
    --oart-cf-hint: rgba(255, 255, 255, .45);
    --oart-cf-error: #FF6A63;
    --oart-cf-send-bg: #FF6A63;
    --oart-cf-send-text: #000;
    --oart-cf-send-h: 52px;
    --oart-cf-send-px: 34px;
    --oart-cf-send-scale: 1.04;

    margin: 0;
}

/* Every row past the first question waits its turn. Rows are revealed by
   adding is-in, exactly as the chat does, so both share one animation. */
.oart-cf__q,
.oart-cf__a,
.oart-cf__closer,
.oart-cf__send-row {
    display: none;
}

.oart-cf__q.is-live,
.oart-cf__a.is-live,
.oart-cf__closer.is-live,
.oart-cf__send-row.is-live {
    display: flex;
}

/* the answer bubble, which is a real input dressed as a bubble */
.oart-cf__field {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    width: var(--oart-cf-answer-w);
    max-width: var(--oart-chat-max);
}

/* This bubble keeps the older proportional padding, on purpose.
   A message bubble holds text, so its padding is worked out from one line box
   (see .oart-chat__bubble). This one holds a real <input>, which the theme pads
   to about 37px, well past a line box, and the confirm arrow is 24px. Measuring
   its padding off a line box would push the bubble roughly 14px past the height
   set for it. The height bug was about message bubbles; this row was already
   sitting where it should, so leave it there. */
.oart-chat__bubble.oart-cf__field {
    padding-block: calc(var(--bm-h) * 0.16);
}

.oart-cf__input {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    /* everything about the type comes from the bubble it sits in, so the
       answer looks written rather than typed into a form field */
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    line-height: inherit;
    caret-color: var(--oart-cf-caret, currentColor);
    resize: none;
    overflow: hidden;
    appearance: none;
}

/* No border, no box, no focus ring. The field is meant to read as a bubble
   someone is speaking into, not a form input. Themes and Elementor both style
   bare inputs and textareas, and an element selector plus a class beats one
   class of ours, which is where the grey box was coming from. Stated across
   the three states firmly enough to win. */
.oart-cf .oart-cf__field .oart-cf__input,
.oart-cf .oart-cf__field .oart-cf__input:hover,
.oart-cf .oart-cf__field .oart-cf__input:focus,
.oart-cf .oart-cf__field .oart-cf__input:focus-visible,
.oart-cf .oart-cf__field .oart-cf__input:active {
    border: 0;
    outline: 0;
    box-shadow: none;
    border-radius: 0;
    background: none;
}

/* The blinking underscore that says "you can type here". It stands in for the
   cursor while the box is empty, so the real caret is hidden for that moment
   and there is only ever one thing blinking. */
.oart-cf__cursor {
    display: none;
    flex: none;
    font: inherit;
    line-height: 1;
    color: var(--oart-cf-caret, currentColor);
    animation: oart-cf-blink 1.05s steps(1) infinite;
}

.oart-cf__a.is-empty:not(.is-answered) .oart-cf__cursor {
    display: inline-block;
}

.oart-cf__a.is-empty:not(.is-answered) .oart-cf__input {
    caret-color: transparent;
}

@keyframes oart-cf-blink {
    0%, 50% { opacity: 1; }
    51%, 100% { opacity: 0; }
}

.oart-cf__input::placeholder {
    color: var(--oart-cf-hint);
    opacity: 1;
}

/* The little arrow that confirms an answer, and the circle behind it. Every
   part of it is a variable so the editor's "Arrow" section owns it.

   It used to be `color: inherit` at `opacity: .5`, so it was always the answer
   text colour, always faded. Willem, 6 August 2026, wanted neither: the colour
   is now its own control and the fade is a control that defaults to full
   strength. Do not put `inherit` or a hard opacity back. */
.oart-cf__ok {
    flex: none;
    display: grid;
    place-items: center;
    width: var(--oart-cf-ok-size, 1.5em);
    height: var(--oart-cf-ok-size, 1.5em);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: var(--oart-cf-ok-bg, transparent);
    color: var(--oart-cf-ok-colour, currentColor);
    cursor: pointer;
    opacity: var(--oart-cf-ok-opacity, 1);
    /* The ring is a box-shadow, NOT a border. A border would eat into the
       content box, so the arrow (sized in %) would shrink the moment a ring
       appeared on hover. A shadow spread draws outside the box and moves
       nothing. */
    box-shadow: 0 0 0 var(--oart-cf-ok-ring, 0px) var(--oart-cf-ok-ring-c, transparent);
    transition: opacity .18s ease, transform .18s ease, color .18s ease,
                background-color .18s ease, box-shadow .18s ease;
}

.oart-cf__ok svg {
    width: var(--oart-cf-ok-icon, 68%);
    height: var(--oart-cf-ok-icon, 68%);
}
/* The path carries stroke-width as a presentation attribute, and any CSS rule
   beats one of those, so the thickness control lands here. */
.oart-cf__ok svg path { stroke-width: var(--oart-cf-ok-stroke, 2.4); }

/* Each hover value falls back to its own resting value, so an empty hover
   control keeps the resting look instead of forcing a colour or a zero. */
.oart-cf__ok:hover {
    color: var(--oart-cf-ok-colour-hover, var(--oart-cf-ok-colour, currentColor));
    background-color: var(--oart-cf-ok-bg-hover, var(--oart-cf-ok-bg, transparent));
    opacity: var(--oart-cf-ok-opacity-hover, var(--oart-cf-ok-opacity, 1));
    box-shadow: 0 0 0 var(--oart-cf-ok-ring-hover, var(--oart-cf-ok-ring, 0px))
                       var(--oart-cf-ok-ring-c-hover, var(--oart-cf-ok-ring-c, transparent));
    transform: translateX(var(--oart-cf-ok-nudge, 2px)) scale(var(--oart-cf-ok-scale, 1));
}
.oart-cf__ok:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* An answered row is a plain bubble again: the field goes read-only rather
   than being swapped for text, so the caret position and any correction the
   visitor makes survive, and the bubble never changes size on the way. */
.oart-cf__a.is-answered .oart-cf__ok { display: none; }
.oart-cf__a.is-answered .oart-cf__input { cursor: default; }

.oart-cf[data-editable="1"] .oart-cf__a.is-answered .oart-cf__field { cursor: pointer; }
.oart-cf[data-editable="1"] .oart-cf__a.is-answered .oart-cf__field:hover { opacity: .82; }

.oart-cf__a.is-answered .oart-cf__input:read-only { cursor: pointer; }

.oart-cf__error {
    position: absolute;
    left: var(--oart-chat-left-inset);
    bottom: -1.15em;
    font-size: .74em;
    line-height: 1;
    color: var(--oart-cf-error);
}

.oart-cf__a.is-wrong .oart-cf__field {
    box-shadow: 0 0 0 2px var(--oart-cf-error);
}

/* the send button, a stadium like the bubbles but its own colour */
.oart-cf__send-row {
    justify-content: flex-end;
    padding-top: 0;
}

.oart-cf__send {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--oart-cf-send-h);
    padding: 0 var(--oart-cf-send-px);
    border: 0;
    border-radius: calc(var(--oart-cf-send-h) / 2);
    background-color: var(--oart-cf-send-bg);
    color: var(--oart-cf-send-text);
    cursor: pointer;
    transition: background-color .2s ease, color .2s ease, transform .2s ease, opacity .2s ease;
}

.oart-cf__send:hover {
    background-color: var(--oart-cf-send-bg-hover, var(--oart-cf-send-bg));
    color: var(--oart-cf-send-text-hover, var(--oart-cf-send-text));
    transform: scale(var(--oart-cf-send-scale));
}

.oart-cf__send:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

.oart-cf.is-sending .oart-cf__send,
.oart-cf.is-sent .oart-cf__send {
    pointer-events: none;
    opacity: .55;
    transform: none;
}

/* once it has gone, the conversation is a record, not a form */
.oart-cf.is-sent .oart-cf__ok,
.oart-cf.is-sent .oart-cf__send-row { display: none; }
.oart-cf.is-sent .oart-cf__field { cursor: default; }

.oart-cf__thanks[hidden] { display: none; }

/* Offscreen rather than display:none. A hidden field is not submitted and
   some bots skip it; this one is in the page and fillable, which is the
   whole point of a honeypot. */
.oart-cf__pot {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* In the editor the whole conversation is laid out at once, or half the
   controls would style something invisible. */
.oart-cf[data-editor="1"] .oart-cf__q,
.oart-cf[data-editor="1"] .oart-cf__a,
.oart-cf[data-editor="1"] .oart-cf__closer,
.oart-cf[data-editor="1"] .oart-cf__send-row {
    display: flex;
}

.oart-cf[data-editor="1"] .oart-chat__bubble {
    opacity: 1;
    transform: none;
}

/* ===================================================================
   Portfolio grid
   True masonry from CSS columns rather than a script: the browser packs
   the tiles itself, so filtering is just display:none and the wall
   repacks with no measuring, no reflow pass and nothing to go wrong on
   a slow connection while images are still arriving.
   =================================================================== */

.oart-pg {
    --oart-pg-cols: 3;
    --oart-pg-gap: 22px;
    --oart-pg-radius: 0px;
    --oart-pg-zoom: 1.06;
    --oart-pg-speed: 340ms;
    --oart-pg-overlay: rgba(0, 0, 0, .72);
    --oart-pg-name: #fff;
    --oart-pg-name-gap: 10px;
    --oart-pg-label: #FF6A63;
    --oart-pg-value: rgba(255, 255, 255, .92);
    --oart-pg-tab-gap: 8px;
    --oart-pg-tabs-bottom: 34px;
    --oart-pg-tab-radius: 4px;
    --oart-pg-tab-text: #2B2B2B;
    --oart-pg-tab-bg: rgba(0, 0, 0, 0);
    --oart-pg-tab-bg-hover: rgba(0, 0, 0, .06);
    --oart-pg-tab-text-active: #fff;
    --oart-pg-tab-bg-active: #FF6A63;
    --oart-pg-ease: cubic-bezier(.22, 1, .36, 1);

    display: block;
}

.oart-pg__empty {
    padding: 14px 18px;
    border: 1px dashed currentColor;
    border-radius: 6px;
    font-size: 12px;
    opacity: .75;
}

/* --- year tabs --- */
.oart-pg__tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--oart-pg-tab-gap);
    margin-bottom: var(--oart-pg-tabs-bottom);
}

.oart-pg__tab {
    border: 0;
    border-radius: var(--oart-pg-tab-radius);
    background-color: var(--oart-pg-tab-bg);
    color: var(--oart-pg-tab-text);
    cursor: pointer;
    line-height: 1;
    transition: background-color var(--oart-pg-speed) var(--oart-pg-ease),
                color var(--oart-pg-speed) var(--oart-pg-ease);
}

.oart-pg__tab:hover {
    background-color: var(--oart-pg-tab-bg-hover);
    color: var(--oart-pg-tab-text-hover, var(--oart-pg-tab-text));
}

.oart-pg__tab.is-active {
    background-color: var(--oart-pg-tab-bg-active);
    color: var(--oart-pg-tab-text-active);
}

.oart-pg__tab:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* --- the wall --- */
.oart-pg__grid {
    column-count: var(--oart-pg-cols);
    column-gap: var(--oart-pg-gap);
}

.oart-pg__item {
    position: relative;
    display: block;
    /* a tile must never be split across two columns */
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    /* the row gap lives in the rule below, which has to outrank Elementor */
    overflow: hidden;
    border-radius: var(--oart-pg-radius);
    /* its own stacking context, so the overlay cannot escape the rounding */
    isolation: isolate;
}

/* CSS multi-column has no row-gap: the space between two tiles in the same
   column can only come from the tile's own bottom margin. Elementor's
   custom-frontend.min.css carries a blanket reset,
     .elementor .elementor-widget:not(...):not(...) figure { margin: 0 }
   which is four classes and an element. A single class of ours loses to it, so
   the gap silently computed to zero and the rows sat flush no matter what the
   control said. Repeating the class outranks it. Measured on the real page, not
   assumed: an isolated test page has none of Elementor's CSS and looks fine
   either way, which is exactly how this was missed the first time. */
.oart-pg .oart-pg__grid > .oart-pg__item.oart-pg__item.oart-pg__item {
    margin: 0 0 var(--oart-pg-row-gap, var(--oart-pg-gap));
}

.oart-pg__item.is-hidden { display: none; }

.oart-pg__img {
    display: block;
    width: 100%;
    height: auto;
    /* the pictures are all different shapes, and that IS the masonry look, so
       nothing is cropped to a common ratio */
    transition: transform var(--oart-pg-speed) var(--oart-pg-ease);
}

.oart-pg__img--none {
    aspect-ratio: 3 / 2;
    background: repeating-linear-gradient(45deg,
        rgba(0, 0, 0, .06) 0 10px, rgba(0, 0, 0, .12) 10px 20px);
}

.oart-pg__item:hover .oart-pg__img,
.oart-pg__item:focus-within .oart-pg__img {
    transform: scale(var(--oart-pg-zoom));
}

/* --- the hover details --- */
.oart-pg__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    background-color: var(--oart-pg-overlay);
    opacity: 0;
    transition: opacity var(--oart-pg-speed) var(--oart-pg-ease);
}

.oart-pg__item:hover .oart-pg__overlay,
.oart-pg__item:focus-within .oart-pg__overlay { opacity: 1; }

.oart-pg__name {
    display: block;
    margin-bottom: var(--oart-pg-name-gap);
    color: var(--oart-pg-name);
}

.oart-pg__facts { display: block; }
.oart-pg__fact { display: block; }
.oart-pg__label { color: var(--oart-pg-label); font-weight: 700; }
.oart-pg__value { color: var(--oart-pg-value); }

/* Touch screens have no hover, so the details would never show at all.
   Shown permanently across the bottom instead of on top of the picture. */
@media (hover: none) {
    .oart-pg__overlay {
        position: static;
        opacity: 1;
        background: none;
        padding-left: 0;
        padding-right: 0;
    }

    .oart-pg__name { color: inherit; }
    .oart-pg__value { color: inherit; }
    .oart-pg__item:hover .oart-pg__img { transform: none; }
}

/* ===================================================================
   Blog post body headings
   The headings inside a post's own copy are bare <h2>/<h3> typed into the
   editor, so they carry no class and land on the theme's reset (2rem) plus
   the kit's body face. That put them in Grift at 32px directly under a page
   title set in Amatry, which is why they read as belonging to another page.
   Willem asked for them smaller and in Amatry, 4 August 2026.

   Scoped to the post content widget ON PURPOSE. The kit's heading settings
   and the Theme Style are both site-wide, so changing either would move
   every heading on every page of the site, which is the same trap the blog
   body size is parked behind.

   The class is repeated to raise specificity to 0,2,1. `.elementor-kit-7 h2`
   sets the font family at 0,1,1 and currently loses only because widgets.css
   happens to be enqueued after post-7.css. Repeating the class means it does
   not matter if that order ever changes.

   Amatry ships exactly ONE face, weight 400 (amatry.woff2, and the browser
   reports a single loaded face). Asking for 600 here would make the browser
   synthesise a fake bold, which smears a display face.
   =================================================================== */

.elementor-widget-theme-post-content.elementor-widget-theme-post-content h2,
.elementor-widget-theme-post-content.elementor-widget-theme-post-content h3 {
    font-family: Amatry, sans-serif;
    font-weight: 400;
    line-height: 1.15;
    letter-spacing: -0.02em;
}

.elementor-widget-theme-post-content.elementor-widget-theme-post-content h2 { font-size: 26px; }
.elementor-widget-theme-post-content.elementor-widget-theme-post-content h3 { font-size: 21px; }

@media (max-width: 767px) {
    .elementor-widget-theme-post-content.elementor-widget-theme-post-content h2 { font-size: 22px; }
    .elementor-widget-theme-post-content.elementor-widget-theme-post-content h3 { font-size: 19px; }
}

/* One breath: out past normal, back through normal, in under it, and home.
   Doing both directions in a single cycle is what makes a shape look like it
   is breathing rather than just pulsing. Keyframes are global, so this sits
   outside the mobile block the rest of the toggle styling lives in. */
@keyframes oart-bmenu-breathe {
    0%   { transform: scale(1); }
    30%  { transform: scale(var(--oart-bmenu-attn-up, 1.18)); }
    65%  { transform: scale(var(--oart-bmenu-attn-down, .88)); }
    100% { transform: scale(1); }
}

/* ===================================================================
   Brand scrollbar
   The browser's own scroll bar in the OART gradient, so it reads like the CTA
   buttons instead of sitting there as grey system furniture.

   Three things to know before changing any of this.

   1. A GRADIENT IS ONLY POSSIBLE THE WEBKIT WAY. The standard properties
      (scrollbar-color, scrollbar-width) take two flat colours and a choice of
      three widths, and that is the whole feature. Firefox supports only those,
      so it gets one brand colour from the @supports block at the bottom.

   2. NEVER ADD scrollbar-color OR scrollbar-width TO THESE SAME ELEMENTS.
      Chrome discards every ::-webkit-scrollbar rule the moment either one is
      present, and says nothing. Measured while building this: a 14px webkit
      bar declared alongside scrollbar-color rendered as the standard 15px one.

   3. On a Mac set to "show scroll bars when scrolling", which is the default,
      none of this is visible until the visitor actually scrolls, and phones
      never show a scroll bar at all. This is a desktop grace note, not a
      load-bearing piece of design.
   =================================================================== */
html {
    --oart-sb-size: 12px;
    --oart-sb-track: rgba(66, 65, 65, .07);
    --oart-sb-rainbow: linear-gradient(180deg, #9B5DF5, #DF31EB, #FF2D96, #FF76BC, #FF6A63, #EF2E2F, #FFA63A);
    --oart-sb-rainbow-h: linear-gradient(90deg, #9B5DF5, #DF31EB, #FF2D96, #FF76BC, #FF6A63, #EF2E2F, #FFA63A);
}

::-webkit-scrollbar {
    width: var(--oart-sb-size);
    height: var(--oart-sb-size);
}

::-webkit-scrollbar-track {
    background: var(--oart-sb-track);
}

/* The transparent border plus background-clip is what leaves a hair of track
   showing down each side, so the thumb reads as a pill rather than a slab. */
::-webkit-scrollbar-thumb {
    background: var(--oart-sb-rainbow);
    border-radius: 99px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

/* A sideways bar needs the gradient turned, or it shows one colour. */
::-webkit-scrollbar-thumb:horizontal {
    background: var(--oart-sb-rainbow-h);
    background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover { filter: brightness(1.08); }

::-webkit-scrollbar-corner { background: var(--oart-sb-track); }

/* Firefox: no gradients on a scroll bar, so one brand colour. This block is
   invisible to Chrome and Safari, which keeps rule 2 above safe. */
@supports not selector(::-webkit-scrollbar) {
    html { scrollbar-color: #FF2D96 rgba(66, 65, 65, .07); }
}

/* ===================================================================
   OART: Categories
   The blog categories as a cascade of speech bubbles.

   Same three-piece mask as the Bubble Menu labels, and the artwork is
   duplicated here rather than shared because those variables are declared on
   .oart-bmenu and do not reach this widget. Artwork is 100.32 x 24.95 with a
   21.17 tall body, which is where 1.1786 (box height) and 0.8818 (cap slice)
   come from. Only the plain band between the caps stretches; stretching the
   whole pill would squash its rounded ends and its point.
   =================================================================== */

.oart-cats {
    --oc-fs: 15px;                 /* text size, drives everything else   */
    --oc-ratio: 2.1;               /* bubble body height, a multiple of it */
    --oc-pad-x: 1.1em;
    --oc-gap: 10px;
    --oc-step: 46px;
    --oc-c: #DF31EB;
    --oc-t: #FFFFFF;
    --oc-hover-scale: 1.05;
    --oc-speed: 180ms;
    --oc-count-opacity: .7;
    --oc-count-size: .8em;

    --oc-pill-l-tail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oc-pill-l-end:  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");
    --oc-pill-r-end:  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    --oc-pill-r-tail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='78.32 0 22 24.95'%3E%3Cpath d='M100.32,24.95l-5.8-11.01c-.16-.31-.19-.66-.12-.99.37-1.62.4-3.37-.13-5.2C92.95,3.09,88.53,0,83.68,0H10.94C5.11,0,.11,4.56,0,10.39c-.11,5.94,4.67,10.78,10.58,10.78h73.51c1.03,0,2.02-.15,2.97-.43.32-.09.66-.1.98,0L100.32,24.95Z'/%3E%3C/svg%3E");
    /* preserveAspectRatio='none' is mandatory on the stretched band. Without it
       an SVG fits its viewBox and centres it, and the whole pill reappears in
       the middle, points and all.

       The viewBox is cropped to 21.17, the body's own height, NOT the full
       24.95 of the artwork. The extra 3.78 is the tail's lane, which is empty
       in the middle of the pill, and stretching a box that includes it left the
       band a hair taller than the two end caps. That overhang draws as a thin
       line along the bottom of every bubble. It is under a pixel at menu-label
       size, which is why the Bubble Menu never showed it, and plainly visible
       once a bubble gets big. Paired with a mask-size height of var(--oc-h)
       below, the band now cannot reach past the body however it is scaled. */
    --oc-pill-mid:    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' viewBox='40 0 20 21.17'%3E%3Cpath d='M0,24.95l5.8-11.01c.16-.31.19-.66.12-.99-.37-1.62-.4-3.37.13-5.2C7.37,3.09,11.79,0,16.64,0h72.75c5.83,0,10.83,4.56,10.93,10.39s-4.67,10.78-10.58,10.78H16.23c-1.03,0-2.02-.15-2.97-.43-.32-.09-.66-.1-.98,0L0,24.95Z'/%3E%3C/svg%3E");

    /* Set by the Arrangement control, which writes all three at once and is
       responsive, so a cascade on a desktop can be flowing rows on a phone. */
    --oc-dir: column;
    --oc-align: flex-start;
    --oc-stagger: 1;
    /* Which side flowing rows sit on. Only bites in row direction, where this
       is the main axis; the stacked arrangements use --oc-align instead. */
    --oc-justify: flex-start;

    display: flex;
    flex-direction: var(--oc-dir);
    flex-wrap: wrap;
    justify-content: var(--oc-justify);
    gap: var(--oc-gap);
}

.oart-cats__bubble {
    /* 1em, not var(--oc-fs): em is this element's OWN font size, so the shape
       follows the text whatever set it. Reading the variable instead meant the
       geometry could be sized off 15px while the text rendered at 24px, and the
       mask then sliced the words off and left a sliver of tail showing. */
    --oc-h: calc(1em * var(--oc-ratio));
    --oc-box: calc(var(--oc-h) * 1.1786);
    --oc-cap: calc(var(--oc-box) * 0.8818);
    /* Sits between the cap's full-height point (0.667) and what the cap masks
       (0.8818) so the band always overlaps the caps. Butting them exactly
       leaves a hairline on fractional widths and the background shows through. */
    --oc-mid: calc(var(--oc-box) * 0.75);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5em;
    box-sizing: border-box;
    align-self: flex-start;
    height: var(--oc-box);
    min-width: calc(var(--oc-cap) * 2);
    /* The bottom padding is the tail's share of the box, so the text stays in
       the body of the pill and never sits over the point. */
    padding: 0 var(--oc-pad-x) calc(var(--oc-box) - var(--oc-h));
    font-size: var(--oc-fs);
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    color: var(--oc-t);
    background-color: var(--oc-c);

    -webkit-mask-image: var(--oc-cap-a), var(--oc-cap-b), var(--oc-pill-mid);
    mask-image: var(--oc-cap-a), var(--oc-cap-b), var(--oc-pill-mid);
    -webkit-mask-repeat: no-repeat, no-repeat, no-repeat;
    mask-repeat: no-repeat, no-repeat, no-repeat;
    -webkit-mask-position: left top, right top, var(--oc-mid) top;
    mask-position: left top, right top, var(--oc-mid) top;
    /* The band is var(--oc-h) tall, the body's height, not the full box. The
       caps stay at 100% because they carry the tail and need the whole height. */
    -webkit-mask-size: auto 100%, auto 100%, calc(100% - var(--oc-mid) * 2) var(--oc-h);
    mask-size: auto 100%, auto 100%, calc(100% - var(--oc-mid) * 2) var(--oc-h);

    transition: transform var(--oc-speed) ease, filter var(--oc-speed) ease;
}

/* Which end carries the point. */
.oart-cats__bubble--left  { --oc-cap-a: var(--oc-pill-l-tail); --oc-cap-b: var(--oc-pill-l-end); }
.oart-cats__bubble--right { --oc-cap-a: var(--oc-pill-r-end);  --oc-cap-b: var(--oc-pill-r-tail); }

a.oart-cats__bubble:hover {
    transform: scale(var(--oc-hover-scale));
    filter: brightness(1.06);
}

.oart-cats__label { display: block; }

.oart-cats__count {
    font-size: var(--oc-count-size);
    opacity: var(--oc-count-opacity);
    font-variant-numeric: tabular-nums;
}

/* ---- Arrangement ----
   All of it comes from the three variables above, so the whole thing is
   switchable per device without a single media query of our own. The cascade
   steps every SECOND bubble across rather than each one a little further: a
   progressive indent walks the last bubbles clean off the right edge. */
.oart-cats__bubble { align-self: var(--oc-align); }

.oart-cats__bubble:nth-child(even) {
    /* min() keeps a desktop-sized step from shoving bubbles off a narrow
       screen even if the arrangement has not been changed for that device. */
    margin-left: min(calc(var(--oc-step) * var(--oc-stagger)), 40vw);
}
