/*
 * Living diagrams: the one motion system behind the globes on /ministries,
 * /groups and /events.
 *
 * The grammar, shared by all three scenes:
 *
 *   globe   the searchable Church: the ecosystem the person is looking into
 *   place   a gold dot
 *   person  the person glyph, a head over shoulders, gold  (#g-person)
 *   you     the same glyph at 1.4x, on a cream knockout, at the near rim
 *   path    discovery or connection, a thin gold line being drawn
 *   ring    a community or a gathering, a dotted ink boundary
 *
 * The person glyph is one <g id="g-person"> in each SVG's <defs>, exactly:
 *
 *   <g id="g-person"><circle cx="0" cy="-4.6" r="2.5"/>
 *     <path d="M-4.6 3.2 A4.6 4.6 0 0 1 4.6 3.2 Z"/></g>
 *
 * and every person is <use href="#g-person" x=… y=…>. It inherits its fill,
 * has no face, no clothing, no gesture: a mark for a human, nothing more.
 *
 * Other kinds of resource are outlined where people are filled, in the same
 * <defs>: #g-building, #g-database, #g-image, #g-note, #g-message. A dotted
 * gold line (stroke-dasharray 2 4) between two resources is what one knows
 * of the other: the network.
 *
 * The parts, each a class, each a way of moving:
 *
 *   .g-globe   the line globe (rim, meridians, latitudes): drifts one degree
 *   .g-merid   the two meridians, clipped to the rim: slide 3px, so the globe
 *              seems to turn under whoever stands on it
 *   .g-glow    rests dim, lights up at its moment
 *   .g-pulse   swells once, gently, at its moment
 *   .g-ring    a thin ring that opens once around a person and fades
 *   .g-trace   a path drawn end to end, kept a moment, let go
 *   .g-trace--keep       the same, kept while the outcome holds (4s)
 *   .g-trace--keep-long  the same, kept for most of the loop (5.6s)
 *   .g-sweep   a short bright length travelling a path: a scan
 *   .g-carry   a small thing carried along a path (--trail on the svg):
 *              a note, a picture, a message going from place to place
 *   .g-arrive  begins a few px away (--dx, --dy) and comes to its place
 *   .g-appear  fades in at its moment and stays a while
 *   .g-open    a ring that widens from .86 to full and brightens: room made
 *   .g-scan    the magnifier, making a small slow pass and coming to rest
 *   .g-lensglow  the lens filling faintly gold when it has found the one
 *
 * arrive, appear and open each have a --long variant that holds longer.
 *
 * Every animation runs on the same clock (--loop, 7s) and every keyframe set
 * ends where it began, so the whole scene is a seamless loop however the
 * parts are offset. A part says when its moment comes with --at (a delay);
 * before that it holds its first keyframe (animation-fill-mode: backwards).
 * Because --at is a custom property it can be set on a <g> and inherited.
 *
 * The SVG attributes are the *outcome*: the arc drawn, the ring open, the
 * members with room made, you stepped in. Keyframes begin displaced from
 * that and arrive at it. Under prefers-reduced-motion every animation is
 * switched off and the outcome alone is shown, so the still picture is the
 * meaningful final state, not an arbitrary frame. Paths that only exist
 * while moving carry opacity="0"; kept paths carry their final opacity on a
 * wrapping <g> so the animated opacity multiplies in.
 *
 * Only transform, opacity and stroke-dashoffset are animated, never layout,
 * and no raster layers are promoted, so the strokes stay vector-crisp at
 * every density and the cost is a small repaint of a 300px drawing.
 */

.globe {
  --loop: 7s;
  --ease: cubic-bezier(.45, .05, .55, .95);   /* slow in, slow out: nothing robotic */
  --draw: cubic-bezier(.4, 0, .2, 1);          /* a line being drawn */
}

.globe [class*="g-"] {
  animation-duration: var(--loop);
  animation-timing-function: var(--ease);
  animation-iteration-count: infinite;
  animation-delay: var(--at, 0s);
  animation-fill-mode: backwards;
}

/* ---- the globe itself ------------------------------------------------- */
.globe .g-globe    { transform-box: fill-box; transform-origin: 50% 50%; animation-name: g-drift; }
.globe .g-merid    { animation-name: g-slide; }

/* ---- people, places, rings -------------------------------------------- */
.globe .g-glow     { animation-name: g-glow; }
.globe .g-pulse    { transform-box: fill-box; transform-origin: center; animation-name: g-pulse; }
.globe .g-ring     { transform-box: fill-box; transform-origin: center; animation-name: g-ring; }
.globe .g-arrive   { animation-name: g-arrive; }
.globe .g-arrive--long { animation-name: g-arrive-long; }
.globe .g-appear   { animation-name: g-appear; }
.globe .g-appear--long { animation-name: g-appear-long; }
.globe .g-open     { transform-box: fill-box; transform-origin: center; animation-name: g-open; }
.globe .g-open--long { transform-box: fill-box; transform-origin: center; animation-name: g-open-long; }

/* ---- paths ------------------------------------------------------------ */
/* Paths carry pathLength="1", so a dash of 1 is the whole line and the offset
   is a fraction of it: 1 hides it, 0 shows it. */
.globe .g-trace        { stroke-dasharray: 1 1; animation-name: g-trace; animation-timing-function: var(--draw); }
.globe .g-trace--keep  { animation-name: g-trace-keep; }
.globe .g-trace--keep-long { animation-name: g-trace-keep-long; }
.globe .g-sweep        { stroke-dasharray: .16 1; animation-name: g-sweep; animation-timing-function: cubic-bezier(.4, .1, .6, .9); }
/* Carried things ride the motion path; where motion paths are not supported
   they keep their resting opacity of 0 rather than sit in the corner. */
@supports (offset-path: path("M0 0h1")) {
  .globe .g-carry { offset-path: var(--trail); offset-rotate: 0deg; transform-box: fill-box; transform-origin: center;
                    animation-name: g-carry; animation-timing-function: cubic-bezier(.4, .1, .6, .9); }
}

/* ---- the lens (Ministries) -------------------------------------------- */
.globe .g-scan     { animation-name: g-scan; }
.globe .g-lensglow { animation-name: g-lensglow; }

/* ---- keyframes: all on the 7s clock, all returning to their start ------ */
@keyframes g-drift { 0%, 100% { transform: rotate(0deg); }   50% { transform: rotate(1deg); } }
@keyframes g-slide { 0%, 100% { transform: translateX(0); }  50% { transform: translateX(3px); } }

@keyframes g-glow  { 0%, 100% { opacity: .38; }  7%, 86% { opacity: 1; } }

@keyframes g-pulse { 0%, 100% { transform: scale(1); }  5% { transform: scale(1.25); }  13% { transform: scale(1); } }

@keyframes g-ring {
  0%, 100% { transform: scale(.7); opacity: 0; }
  3%       { opacity: .7; }
  16%      { transform: scale(1.6); opacity: 0; }
}

/* A moment, a hold, a return. Brief holds 3.1s, long holds 4.6s. */
@keyframes g-arrive {
  0%, 100% { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
  7%, 36%  { transform: translate(0, 0); }
  44%      { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
}
@keyframes g-arrive-long {
  0%, 100% { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
  7%, 58%  { transform: translate(0, 0); }
  66%      { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
}

@keyframes g-appear      { 0%, 100% { opacity: 0; }  7%, 36% { opacity: 1; }  44% { opacity: 0; } }
@keyframes g-appear-long { 0%, 100% { opacity: 0; }  7%, 58% { opacity: 1; }  66% { opacity: 0; } }

@keyframes g-open {
  0%, 100% { transform: scale(.86); opacity: .7; }
  7%, 36%  { transform: scale(1);   opacity: 1; }
  44%      { transform: scale(.86); opacity: .7; }
}
@keyframes g-open-long {
  0%, 100% { transform: scale(.86); opacity: .7; }
  7%, 58%  { transform: scale(1);   opacity: 1; }
  66%      { transform: scale(.86); opacity: .7; }
}

@keyframes g-trace {
  0%        { stroke-dashoffset: 1.02; opacity: 0; }
  3%        { opacity: 1; }
  16%       { stroke-dashoffset: 0; }
  28%       { stroke-dashoffset: 0; opacity: 1; }
  36%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes g-trace-keep {
  0%        { stroke-dashoffset: 1.02; opacity: 0; }
  3%        { opacity: 1; }
  16%       { stroke-dashoffset: 0; }
  47%       { stroke-dashoffset: 0; opacity: 1; }
  57%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes g-trace-keep-long {
  0%        { stroke-dashoffset: 1.02; opacity: 0; }
  3%        { opacity: 1; }
  16%       { stroke-dashoffset: 0; }
  70%       { stroke-dashoffset: 0; opacity: 1; }
  80%, 100% { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes g-sweep {
  0%        { stroke-dashoffset: .16; opacity: 0; }
  3%        { opacity: 1; }
  30%       { opacity: 1; }
  33%, 100% { stroke-dashoffset: -1; opacity: 0; }
}

@keyframes g-carry {
  0%        { offset-distance: 0%;   opacity: 0; }
  3%        { opacity: 1; }
  30%       { opacity: 1; }
  33%, 100% { offset-distance: 100%; opacity: 0; }
}

@keyframes g-scan {
  0%, 28%, 100% { transform: translate(0, 0); }
  9%            { transform: translate(-5px, 4px); }
  18%           { transform: translate(-2px, 7px); }
}

@keyframes g-lensglow { 0%, 100% { opacity: 0; }  7%, 40% { opacity: .2; }  48% { opacity: 0; } }

/* Under reduced motion the diagram stands still at its outcome. */
@media (prefers-reduced-motion: reduce) {
  .globe * { animation: none !important; }
}
