/* 2014 / 2026 mode switch  (markup: index.html .mode-toggle + #mode-toggle-panel; behaviour: js/mode-toggle.js)
 * Colors match _colors.scss ($accent #1295ff, $darkblue #0a5c86, $darkgrey #555555,
 * $offblack #2f2f2f, $offwhite #EDEDED, $lightgrey #b1b1b1).
 *
 * Peg states (classes set by js/mode-toggle.js), in order. The story: "I'm trying to
 * toggle... struggling..." then, after a beat, "aha! it's not implemented yet".
 *   (none)                         round peg rests at 2014
 *   .is-loading.is-struggling      peg pushes toward the middle of the track against
 *                                  resistance, getting knocked back, slowing as it nears the
 *                                  middle (--struggle-time): the "API call"
 *   .is-loading                    holds at the middle for a beat (BEAT_MS in the JS)
 *   .is-loading.is-alert           "aha": the round peg swells slightly and squares up
 *                                  (realization, attention!), then shrinks into the dot of a
 *                                  "!" while the bar of the "!" extends down above it (and the
 *                                  toast peeks out, see Toast)
 *   .is-loading (again)            "!" folds back into the round peg, still mid-track
 *   (none again)                   then the peg springs home
 * A transition is taken from the state being ENTERED, so each rule below carries the
 * timing for arriving in that state; the resting rule carries the springy return. */
.mode-toggle {
    --peg-size: .6rem;                           /* the round peg's diameter */
    --track-pad-x: calc(2px + var(--peg-drop));  /* side padding = the peg's top/bottom gap, so at rest the peg
                                                    sits centered in the pill's rounded end, evenly spaced */
    --peg-travel: calc(3.25rem - 4px - 2 * var(--track-pad-x) - var(--peg-size)); /* track width - borders - side padding - peg */
    --peg-stop: calc(var(--peg-travel) * .5);    /* where the peg gives up: the exact middle of the track */
    --peg-drop: calc((1.6rem - 8px - var(--peg-size)) / 2); /* gap above and below the centered peg; the dot drops by this */
    --struggle-time: 1200ms;                     /* = STRUGGLE_MS in the JS */
    --swell-time: 200ms;                         /* the realization: peg swells and squares up before becoming the dot */
    --bang-time: 250ms;                          /* shrinking into the dot, after the swell */
    --unbang-time: 200ms;                        /* "!" folding back to the peg; UNBANG_MS in the JS waits this long */
    --mark-width: 5px;                           /* thickness of the "!" bar and dot */
    position: absolute;
    top: .25rem;                                 /* level with the .identity logo box: both span 4.8px-46.4px, */
    left: 50%;                                   /* so the switch and its shadow stay inside the white bar */
    transform: translateX(-50%);
    font-family: brandon-grotesque, "Brandon Grotesque", "Helvetica Neue", sans-serif;
    text-transform: uppercase;
    font-weight: bold;
    z-index: 2;
}

/* Two classes on purpose: _header.scss has ".navbar button { margin-right: 10vw !important }",
   and an !important override only wins with equal or higher specificity (here 0,2,0 vs 0,1,1). */
.mode-toggle .mode-toggle-switch { margin-right: 0 !important; }
.mode-toggle-switch {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .7rem;                    /* makes the switch 41.6px tall, the logo box's height */
    border: 2px solid #2f2f2f;               /* framed like a badge, with the .identity hard shadow in accent blue */
    background: white;
    box-shadow: 4px 4px 0 0 #1295ff;
    color: #555555;
    font: inherit;
    font-size: .9rem;
    letter-spacing: .05em;
    cursor: pointer;
}
.mode-toggle-switch:focus-visible {
    outline: 3px solid #0a5c86;
    outline-offset: 2px;
}
.mode-toggle-label.is-current { color: #1295ff; }

/* Track: a pill (rectangle with fully rounded ends). Peg: a small circle, vertically centered.
   Two separate shape controls, each animating smoothly:
     border-radius  round (50%) <-> square (0): the "aha" squares it up
     clip-path      whole peg (inset 0) <-> small square at its bottom center: the "!" dot */
.mode-toggle-track {
    position: relative;                          /* anchors the "!" bar (::before) */
    display: block;
    width: 3.25rem;
    height: 1.6rem;
    padding: 2px var(--track-pad-x);
    border: 2px solid #2f2f2f;
    border-radius: 999px;                        /* pill: straight sides, fully rounded ends */
    background: #EDEDED;
}
.mode-toggle-peg {
    display: block;
    width: var(--peg-size);
    height: var(--peg-size);
    margin-top: var(--peg-drop);                 /* centered vertically in the track */
    background: #1295ff;
    translate: 0;
    border-radius: 50%;                          /* round */
    clip-path: inset(0);                         /* the whole peg showing */
    transition:
        translate 450ms cubic-bezier(.34, 1.56, .64, 1),           /* return: overshoots a little, springs home */
        clip-path var(--unbang-time) ease-out,                      /* (already whole and round by now; */
        border-radius var(--unbang-time) ease-out;                  /*  kept for safety) */
}
.mode-toggle.is-loading .mode-toggle-peg {
    translate: var(--peg-stop);                                     /* middle of the track, never all the way */
    transition:                                                     /* release, part 1: "!" -> peg, still mid-track */
        clip-path var(--unbang-time) ease-out,                      /* dot grows back into the full peg, */
        translate var(--unbang-time) ease-out,                      /* rises back to center, */
        border-radius var(--unbang-time) ease-out;                  /* and rounds off into a circle again */
}                                                                   /* (on arrival the struggle animation overrides this) */

/* The struggle: pushing against resistance.
   Each push starts slow and builds speed (ease-in) until it hits the resistance; each
   knock-back is a quick snap (short, ease-out). The pushes get shorter and slower as the
   peg nears the middle, and the last one eases in to a stop.
   Timing functions set inside a keyframe apply to the stretch that FOLLOWS that keyframe.
   The last frame equals the .is-loading position, so the peg stays put when it ends. */
.mode-toggle.is-struggling .mode-toggle-peg {
    animation: mode-toggle-struggle var(--struggle-time) linear;
}
@keyframes mode-toggle-struggle {
    0%   { translate: 0;                              animation-timing-function: ease-in; }   /* push 1 */
    30%  { translate: calc(var(--peg-stop) * .75);   animation-timing-function: ease-out; }  /* knocked back */
    38%  { translate: calc(var(--peg-stop) * .5);    animation-timing-function: ease-in; }   /* push 2, shorter */
    66%  { translate: calc(var(--peg-stop) * .88);   animation-timing-function: ease-out; }  /* knocked back, less */
    73%  { translate: calc(var(--peg-stop) * .72);   animation-timing-function: cubic-bezier(.45, 0, .25, 1); } /* push 3: slow in, slow out */
    100% { translate: var(--peg-stop); }                                                       /* made it to the middle */
}

/* The "aha":
   1. the realization (--swell-time): the round peg swells a little (`scale`) and settles
      back, squaring up (border-radius -> 0) as it does: attention!
   2. then it becomes the dot of a "!": clipped down to a --mark-width square at its bottom
      center, while the peg drops by --peg-drop so the dot lands on the track's floor
      (--bang-time, delayed by the swell)
   The bar of the "!" is drawn on the track above where the peg stopped and is revealed
   top-to-bottom, so it reads as extending down (.mode-toggle-track::before below).
   `translate` and `scale` are separate properties, so the swell grows from the peg's own
   center wherever the slide left it. */
.mode-toggle.is-loading.is-alert .mode-toggle-peg {
    translate: var(--peg-stop) var(--peg-drop);
    border-radius: 0;
    clip-path: inset(calc(100% - var(--mark-width)) calc(50% - var(--mark-width) / 2) 0 calc(50% - var(--mark-width) / 2));
    transition:
        border-radius var(--swell-time) ease-out,                   /* 1: squares up during the swell */
        clip-path var(--bang-time) ease-in var(--swell-time),       /* 2: then shrinks to the dot... */
        translate var(--bang-time) ease-in var(--swell-time);       /*    ...and drops onto the floor */
    animation: mode-toggle-swell var(--swell-time) ease-out;
}
@keyframes mode-toggle-swell { 50% { scale: 1.2; } }
.mode-toggle-track::before {
    content: "";
    position: absolute;
    top: 2px;                                                       /* the track's padding */
    left: calc(var(--track-pad-x) + var(--peg-stop) + var(--peg-size) / 2 - var(--mark-width) / 2); /* side padding + peg's stop + half the peg - half the bar */
    width: var(--mark-width);
    height: calc(100% - 4px - var(--mark-width) - 2px);           /* track inner height - dot - 2px gap */
    background: #1295ff;
    clip-path: inset(0 0 100% 0);                                   /* hidden: nothing revealed yet */
    transition: clip-path 150ms ease-in;                            /* on release: retracts upward, quickly */
}
.mode-toggle.is-alert .mode-toggle-track::before {
    clip-path: inset(0);
    transition: clip-path 250ms ease-out 250ms;                     /* starts as the dot is forming, after the swell */
}
.mode-toggle.is-loading .mode-toggle-switch { cursor: progress; }  /* busy pointer for the whole run: part of the act */

/* Toast: the response.
 * It is a direct child of <header> (index.html), and <header> is its own stacking layer
 * (.fixer z-index in _header.scss). Inside that layer, z-index -1 paints the toast BEHIND
 * the white navbar, so it drops out from under the bar's bottom edge (top: 100%, no gap)
 * and slides back up under it.
 * It peeks out in the same moment the peg turns into a "!", then slides back in during
 * the same 450ms as the peg's return (.mode-toggle-peg above): the two move as one.
 * The slide uses `translate`, leaving `transform` free for the horizontal centering. */
.mode-toggle-panel {
    --leave-time: 450ms;                         /* = the peg's return; keep equal to LEAVE_MS in the JS */
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    z-index: -1;
    width: max-content;
    max-width: calc(100vw - 32px);
    padding: .6rem 1rem;
    background: #2f2f2f;
    color: white;
    font-family: brandon-grotesque, "Brandon Grotesque", "Helvetica Neue", sans-serif;
    font-size: .95rem;
    font-weight: bold;
    box-shadow: 5px 5px 0 0 #555555;
    animation: mode-toggle-enter 450ms cubic-bezier(.34, 1.56, .64, 1);   /* springy drop, overshoots a touch */
}
.mode-toggle-panel[hidden] { display: none; }
.mode-toggle-panel.is-leaving { animation: mode-toggle-leave var(--leave-time) ease-in forwards; }
@keyframes mode-toggle-enter { from { translate: 0 -100%; } }
@keyframes mode-toggle-leave { to { translate: 0 -100%; } }

/* When the header slides up (portfolio.js removes .shower), the toast hangs below it
   and would be left stranded at the top of the page. Hide it with the header. */
header:not(.shower) .mode-toggle-panel { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
    .mode-toggle-peg,
    .mode-toggle.is-struggling .mode-toggle-peg,
    .mode-toggle.is-loading.is-alert .mode-toggle-peg { animation: none; }   /* no struggle, no swell */
    .mode-toggle-panel { animation: none; }
    .mode-toggle-panel.is-leaving { animation: mode-toggle-fade var(--leave-time) ease-in forwards; }
    @keyframes mode-toggle-fade { to { opacity: 0; } }
}

/* Phones: the brand fills the left side, so tuck the switch under the bar on the right,
   and drop the toast below the switch instead of straight off the bar. */
@media (max-width: 767px) {
    .mode-toggle {
        top: auto;
        bottom: -2.1rem;
        left: auto;
        right: 10vw;
        transform: none;
    }
    .mode-toggle-panel {
        top: calc(100% + 2.6rem);
        left: auto;
        right: 10vw;
        transform: none;
    }
    /* Hanging below the bar, the switch would peek out while the header is slid
       up. Hide it until portfolio.js adds .shower on scroll, like the rest of the navbar. */
    header:not(.shower) .mode-toggle { visibility: hidden; }
}
