/* Animated Meta4D mark (Views/Shared/_BrandLoader.cshtml).

   Two phases:
   - Once, on arrival: the hexagon draws itself (0–0.8 s) and the drone lands on the top node
     (0.55–0.95 s). Both then stay put — the frame is never redrawn.
   - Forever after, inside the frame (the "loading" part, one 2 s cycle from 0.9 s):
       0–35 %   the scan lines run down from the drone
      25–50 %   the side nodes, then the ground node, land
      50–80 %   the ground node sends out a pulse — the scan
      86–100 %  the lines and nodes fade, and the scan starts again
     The drone hovers and its rotors spin the whole time.
   Reduced motion: the finished mark sits still and breathes. */

.brand-loader {
    --brand-loader-cycle: 2s;
    --brand-loader-start: 0.9s;
    --brand-loader-accent: var(--bs-primary);
    display: block;
    width: 1em;
    height: 1em;
    overflow: visible;
    color: inherit;
}

/* ── Once ─────────────────────────────────────────────── */
.brand-loader-hex {
    fill: none;
    stroke: currentColor;
    stroke-width: 6.5;
    stroke-linejoin: miter;
    stroke-dasharray: 1;
    animation: brand-loader-draw 0.8s cubic-bezier(0.65, 0, 0.35, 1) both;
}

/* The drone, seen from above. Scaled from the node's centre (view-box units), so it grows out of
   the node rather than out of a corner. */
.brand-loader-drone {
    transform-box: view-box;
    transform-origin: 49.6px 23.8px;
    animation: brand-loader-land 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0.55s both;
}

.brand-loader-hover {
    animation: brand-loader-hover 1.4s ease-in-out infinite;
}

.brand-loader-arms {
    fill: none;
    stroke: var(--brand-loader-accent);
    stroke-width: 2.2;
    stroke-linecap: round;
}

/* Two blades per rotor (a dashed ring), turning fast; neighbours counter-rotate like a real quad. */
.brand-loader-rotor {
    fill: none;
    stroke: var(--brand-loader-accent);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-dasharray: 7 5.6;
    transform-box: fill-box;
    transform-origin: center;
    animation: brand-loader-rotor 0.35s linear infinite;
}

.brand-loader-rotor-ccw { animation-direction: reverse; }

.brand-loader-node,
.brand-loader-ring {
    fill: var(--brand-loader-accent);
    transform-box: fill-box;
    transform-origin: center;
}

/* ── Forever: the scan inside the frame ──────────────── */
.brand-loader-lines path {
    fill: none;
    stroke: var(--brand-loader-accent);
    stroke-width: 4.5;
    stroke-linecap: round;
    stroke-dasharray: 1;
    animation: brand-loader-line var(--brand-loader-cycle) ease-out var(--brand-loader-start) infinite both;
}

/* Top edges first, then the drop, then the two that close the pyramid onto the ground node. */
.brand-loader-lines path:nth-child(3) { animation-name: brand-loader-line-drop; }
.brand-loader-lines path:nth-child(4),
.brand-loader-lines path:nth-child(5) { animation-name: brand-loader-line-close; }

.brand-loader-node-left,
.brand-loader-node-right {
    animation: brand-loader-node-side var(--brand-loader-cycle) cubic-bezier(0.34, 1.56, 0.64, 1) var(--brand-loader-start) infinite both;
}

.brand-loader-node-bottom {
    animation: brand-loader-node-bottom var(--brand-loader-cycle) cubic-bezier(0.34, 1.56, 0.64, 1) var(--brand-loader-start) infinite both;
}

.brand-loader-ring {
    fill: none;
    stroke: var(--brand-loader-accent);
    stroke-width: 2;
    animation: brand-loader-ring var(--brand-loader-cycle) ease-out var(--brand-loader-start) infinite both;
}

@keyframes brand-loader-draw {
    from { stroke-dashoffset: 1; }
    to   { stroke-dashoffset: 0; }
}

@keyframes brand-loader-land {
    from { transform: scale(0); }
    to   { transform: scale(1); }
}

@keyframes brand-loader-hover {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-1.6px); }
}

@keyframes brand-loader-rotor {
    to { transform: rotate(360deg); }
}

@keyframes brand-loader-line {
    0%        { stroke-dashoffset: 1; opacity: 1; }
    18%, 86%  { stroke-dashoffset: 0; opacity: 1; }
    100%      { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes brand-loader-line-drop {
    0%, 8%    { stroke-dashoffset: 1; opacity: 1; }
    28%, 86%  { stroke-dashoffset: 0; opacity: 1; }
    100%      { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes brand-loader-line-close {
    0%, 18%   { stroke-dashoffset: 1; opacity: 1; }
    38%, 86%  { stroke-dashoffset: 0; opacity: 1; }
    100%      { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes brand-loader-node-side {
    0%, 16%   { transform: scale(0); opacity: 1; }
    28%, 86%  { transform: scale(1); opacity: 1; }
    100%      { transform: scale(1); opacity: 0; }
}

@keyframes brand-loader-node-bottom {
    0%, 36%   { transform: scale(0); opacity: 1; }
    48%, 86%  { transform: scale(1); opacity: 1; }
    100%      { transform: scale(1); opacity: 0; }
}

@keyframes brand-loader-ring {
    0%, 48%   { transform: scale(1); opacity: 0; }
    50%       { transform: scale(1); opacity: 0.9; }
    80%, 100% { transform: scale(3.2); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .brand-loader-hex,
    .brand-loader-lines path,
    .brand-loader-node,
    .brand-loader-drone,
    .brand-loader-hover,
    .brand-loader-rotor {
        stroke-dashoffset: 0;
        transform: none;
        opacity: 1;
        animation: none;
    }
    .brand-loader-ring { display: none; }
    .brand-loader { animation: brand-loader-breathe 1.6s ease-in-out infinite; }
}

@keyframes brand-loader-breathe {
    0%, 100% { opacity: 0.55; }
    50%      { opacity: 1; }
}

/* The sign-in waiting screens (Google return, sign out) and the plan list while it loads:
   the mark in place of a spinner, centred above the heading. */
.auth-wait-mark {
    display: flex;
    justify-content: center;
    margin-bottom: 1rem;
    font-size: 56px;
    color: var(--bs-emphasis-color);
}

.sp-loading .brand-loader {
    font-size: 56px;
    margin: 0 auto 12px;
}

/* ── The app's one loader (Shared/_PageLoader.cshtml, js/page-loader.js) ──
   The mark and what is loading, centred. Page: the whole content area. Compact: inside a card
   or panel. currentColor draws the hexagon, so it follows the theme's ink. */
.page-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    min-height: 60vh;
    color: var(--bs-emphasis-color);
}

.page-loader .brand-loader {
    font-size: 64px;
}

.page-loader--compact {
    min-height: 0;
    padding: 48px 16px;
    gap: 12px;
}

.page-loader--compact .brand-loader {
    font-size: 44px;
}

.page-loader-text {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--bs-secondary-color);
    letter-spacing: 0.01em;
    text-align: center;
}
