/* IPS Team Orbit - frontend
 *
 * ZERO JAVASCRIPT. Everything below is CSS:
 *   - a person sits at the TOP of their ring, and the ring is rotated to move
 *     them around it
 *   - the face is kept upright by TWO cancellations on two separate elements
 *   - pause on hover is animation-play-state
 *
 * Every value the panel controls is read from a custom property. The stylesheet
 * only READS them, so no control can be beaten by a rule in here, and there is
 * no !important anywhere.
 *
 * THE GEOMETRY IS DELIBERATELY PERCENTAGE-BASED, and that decides the markup.
 * The obvious build is rotate(theta) then translateY(-radius), but a percentage
 * translate resolves against the ELEMENT's own box, not its container, so the
 * radius could not be a share of the stage and nothing would scale on a phone.
 * Instead the slot fills the whole ring and the avatar is pinned to the ring's
 * top edge: then every size is a percentage of the stage and one width control
 * scales the entire diagram.
 */

.ips-to {
	--ips-to-stage: 760px;
	--ips-to-hub: 120px;
	--ips-to-avatar: 60px;
	--ips-to-duration: 36s;

	/* ring DIAMETERS, as a share of the stage */
	--ips-to-d1: 41%;
	--ips-to-d2: 69%;
	--ips-to-d3: 92%;

	--ips-to-orbit-color: rgba(255, 255, 255, .18);
	--ips-to-orbit-width: 1px;

	--ips-to-avatar-ring: rgba(255, 255, 255, .14);
	--ips-to-avatar-ring-width: 6px;
	--ips-to-avatar-ring-hover: rgba(255, 255, 255, .85);
	--ips-to-avatar-shadow: 0 6px 18px rgba(0, 0, 0, .35);

	--ips-to-hub-bg: #ffffff;
	--ips-to-hub-pad: 22px;
	--ips-to-hub-radius: 50%;
	--ips-to-hub-shadow: 0 10px 40px rgba(0, 0, 0, .25);

	display: flex;
	justify-content: center;

	/* A ROTATED SQUARE HAS A BIGGER BOUNDING BOX than the square, by up to a
	   factor of root 2, and that box still takes part in layout even though
	   only the inscribed circle is visible. Measured on a 390px phone: the
	   rings widened the document by 97px and gave the whole PAGE a sideways
	   scrollbar. Clipping here contains those invisible boxes; the stage is
	   sized below so nothing visible ever reaches this edge. */
	overflow: hidden;
}

/* The stage is a SQUARE and every inner size is a percentage of it, so the one
   width control scales the whole diagram. min() keeps it inside a narrow column
   without needing a breakpoint of its own. */
.ips-to__stage {
	position: relative;
	/* Leave one photo's width of room: an avatar is pinned to the ring's edge
	   and so sticks out half its own width beyond the stage, on both sides.
	   Without this the outer photos and their halos would meet the clip above. */
	width: min(var(--ips-to-stage), calc(100% - var(--ips-to-avatar)));
	aspect-ratio: 1 / 1;
}

/* ---------------------------------------------------------------- rings */

/* Centred with left/top and a negative margin rather than a centring
   transform, because `transform` has to stay free for the spin. Percentage
   margins resolve against the containing block's WIDTH, which is the square
   stage, so this stays centred at every size. */
.ips-to__ring {
	position: absolute;
	left: 50%;
	top: 50%;
	width: var(--ips-to-ring-d);
	height: var(--ips-to-ring-d);
	margin-left: calc(var(--ips-to-ring-d) / -2);
	margin-top: calc(var(--ips-to-ring-d) / -2);
	border-radius: 50%;
	animation: ips-to-spin var(--ips-to-duration) linear infinite;
}

.ips-to--orbits .ips-to__ring {
	border: var(--ips-to-orbit-width) solid var(--ips-to-orbit-color);
}

/* Alternating direction is what makes it read as an orbit and not a wheel. */
.ips-to__ring--ccw {
	animation-direction: reverse;
}

/* ---------------------------------------------------------------- slots */

/* One slot per person, filling the ring. Its angle comes from the person's
   index, handed down by PHP as --ips-to-i; the step is 360deg divided by the
   number of people on THIS ring. Index 0 lands at twelve o'clock. */
.ips-to__slot {
	position: absolute;
	inset: 0;
	transform: rotate(calc(var(--ips-to-i) * var(--ips-to-step) + var(--ips-to-offset, 0deg)));
}

/* TWO cancellations, and they cannot share an element.
 *
 * The face has to undo the ring's ANIMATED rotation and the slot's STATIC one.
 * Both on one element does not work: while an animation is running it overrides
 * that element's own transform declaration, so the static counter-rotation is
 * dropped and every face tilts. So __counter carries the animation (same
 * duration, opposite direction) and __avatar carries the static angle.
 */
.ips-to__counter {
	position: absolute;
	left: 50%;
	top: 0;
	width: var(--ips-to-avatar);
	height: var(--ips-to-avatar);
	margin-left: calc(var(--ips-to-avatar) / -2);
	margin-top: calc(var(--ips-to-avatar) / -2);
	animation: ips-to-spin var(--ips-to-duration) linear infinite reverse;
}

.ips-to__ring--ccw .ips-to__counter {
	animation-direction: normal;
}

.ips-to__avatar {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	transform: rotate(calc((var(--ips-to-i) * var(--ips-to-step) + var(--ips-to-offset, 0deg)) * -1));
}

.ips-to__avatar img {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	object-fit: cover;
	box-shadow:
		0 0 0 var(--ips-to-avatar-ring-width) var(--ips-to-avatar-ring),
		var(--ips-to-avatar-shadow);
	transition: box-shadow .25s ease, transform .25s ease;
}

.ips-to__avatar:hover img,
.ips-to__avatar:focus-visible img {
	box-shadow:
		0 0 0 var(--ips-to-avatar-ring-width) var(--ips-to-avatar-ring-hover),
		var(--ips-to-avatar-shadow);
	transform: scale(1.08);
}

.ips-to__avatar:focus-visible {
	outline: 2px solid var(--ips-to-avatar-ring-hover);
	outline-offset: 4px;
}

/* ------------------------------------------------------------------ hub */

.ips-to__hub {
	position: absolute;
	left: 50%;
	top: 50%;
	width: var(--ips-to-hub);
	height: var(--ips-to-hub);
	margin-left: calc(var(--ips-to-hub) / -2);
	margin-top: calc(var(--ips-to-hub) / -2);
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	padding: var(--ips-to-hub-pad);
	background: var(--ips-to-hub-bg);
	border-radius: var(--ips-to-hub-radius);
	box-shadow: var(--ips-to-hub-shadow);

	/* A LOGO CAN PAINT OUTSIDE ITS OWN BOX, and an <img> then clips it to a
	   SQUARE. The house logo is an animated SVG whose pulse rings scale to
	   3.2x with overflow:visible; inside an <img> that overflow is cut off at
	   the image's rectangle, which drew a hard-edged teal square around the
	   badge on /awards/. Clip to the badge's own shape instead. */
	overflow: hidden;
}

.ips-to__hub img {
	display: block;
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	/* Follow the badge's shape, so a logo that paints to its own edges is
	   rounded with it rather than showing its corners. `inherit` keeps a
	   square-cornered badge square. This is the RASTER path; an SVG logo is
	   rendered inline instead (below) and needs no such rounding. */
	border-radius: inherit;
}

/* AN SVG LOGO IS RENDERED INLINE, not as an <img>, and this is why: an <img>
   always clips SVG content to the image's own rectangle, so a logo that
   animates outside its box is cut off at a square edge. Measured on the house
   logo, whose pulse rings scale to 3.2x: through an <img> the visible ring
   reached 40.5px and 3.2% of pixels changed over a loop; inline it reaches 78px
   and 49.1%. Inline it can paint outside its box, and the badge's own overflow
   decides how far it gets. */
.ips-to__hub svg {
	display: block;
	width: 100%;
	height: 100%;
	overflow: visible;
}

/* Let the logo's animation spread past the badge instead of being clipped to
   it. Off by default: unclipped, the house logo's halo reaches well into the
   inner orbit. */
.ips-to--hubspread .ips-to__hub {
	overflow: visible;
}

/* ---------------------------------------------------------------- pause */

/* Pausing lets someone read or click a face instead of chasing it. BOTH
   animations must pause, or the counter-rotation keeps running and the photos
   spin on the spot. focus-within covers the same thing for the keyboard. */
.ips-to--pause .ips-to__stage:hover .ips-to__ring,
.ips-to--pause .ips-to__stage:hover .ips-to__counter,
.ips-to--pause .ips-to__stage:focus-within .ips-to__ring,
.ips-to--pause .ips-to__stage:focus-within .ips-to__counter {
	animation-play-state: paused;
}

@keyframes ips-to-spin {
	from { transform: rotate(0deg); }
	to   { transform: rotate(360deg); }
}

/* Someone who has asked their system not to animate still gets the diagram.
   The arrangement is the point; the motion is decoration. */
@media (prefers-reduced-motion: reduce) {
	.ips-to__ring,
	.ips-to__counter {
		animation: none;
	}
}

/* ----------------------------------------------------------- the editor */

/* An empty widget must still be visible and selectable in the builder, or it
   looks broken and cannot be clicked. Keyed on html.elementor-html, never
   body.elementor-editor-active: Elementor 4.x removes that body class from the
   preview on documents/open and panel/open, so a guard built on it silently
   stops working. The animation is deliberately LEFT RUNNING here, so the motion
   can be judged in the editor rather than only on the live page. */
html.elementor-html .ips-to__stage {
	min-height: 140px;
}
