/* mobile-tabbar.css — shikki.io mobile navigation bar.
 *
 * Chosen from _tabbar-gallery.html (20 candidates, 4 groups). Every effect
 * here was picked against three quiet siblings at 22px, not in isolation —
 * which is the only way the choice means anything.
 *
 * SELECTION — one discrete effect per tab, fired on the newly selected icon
 * only, non-repeating. Same contract as AnimatedTabView.swift in WabiSabi
 * (`addSymbolEffect(effect, options: .nonRepeating)` in onChange).
 *
 *     GET SHIKKI   ignite          the mark is a flame, and it warms up FROM
 *                                  the inactive grey rather than starting lit
 *     FLOW         phosphor flash  anim-hero-logo-in's phosphor seed
 *     FEATURES     CRT degauss     anim-hero-logo-burst
 *     CONTACT      hue drift       walks the Dracula accents, zero geometry
 *
 * Two of those four are the hero's own animations at tab scale, so the bar
 * belongs to the terminal the page opens on rather than decorating it.
 *
 * IDLE — a rare effect on the ALREADY-selected icon, 8–30s apart. Operator
 * intent: a screensaver, not a demo. "I don't want people see it, I want it's
 * like the old screensaver who arrive for a while." So it is deliberately NOT
 * biased to fire early — being missed most of the time is the feature.
 *
 * The idle pool is WEIGHTED, not uniform (see mobile-tabbar.js). The four
 * non-displacing effects — pulse, breathe, hue drift, cursor blink — change
 * the icon without moving it, so peripheral vision is not yanked off the
 * content. bounce / wiggle / rotate stay in as rare accents.
 *
 * Ink bloom and settle are NOT in the idle pool. Both are entrance
 * animations — ink bloom resolves from blurred scale(0.72), settle drops from
 * -9px — so firing them on an icon that has sat there for 20 seconds says
 * "this just appeared" when nothing did. They run once, on the bar's first
 * paint, where that reading is true.
 */

.mobile-tabbar {
  display: none;   /* desktop/tablet: the header nav owns navigation */
}

@media (max-width: 480px),
       (orientation: landscape) and (max-width: 1000px) and (max-height: 480px) {
  .mobile-tabbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 8000;               /* under the waitlist sheet (9000) */
    display: flex;
    /* CENTRE, not flex-end. Bottom-anchoring the tabs meant every pixel of
       top padding landed ABOVE the plate and none below it — measured 13px
       over the highlight against 6px under it, so the hover plate read as
       sitting low in the bar however the padding was tuned. Centring is what
       actually makes the space equal; the padding only sets how much.
       (flex-end was there to line up tabs of differing heights. All four are
       icon + one label, so there is nothing left for it to align.) */
    align-items: center;
    justify-content: space-around;
    gap: 2px;
    /* Equal on all four sides, so the plate has the same air above, below and
       beside it. Any change here changes the bar's HEIGHT, which is fine:
       main.js measures the bar into `--tabbar-h` and the terminal frame's
       bottom follows it — a one-number change rather than a number to keep in
       sync with the frame's geometry. */
    padding: 10px 10px calc(10px + env(safe-area-inset-bottom));
    /* The gallery's stage look, which the operator asked to keep whole:
       terminal ground, purple hairline, radius on the top corners only
       since the bar is flush to the bottom edge. */
    background: var(--terminal-bg, #1c1d2a);
    border-top: 1px solid rgba(189, 147, 249, 0.3);
    border-radius: 10px 10px 0 0;
    overflow: hidden;
    transition: transform 260ms cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* CRT scanlines, as in the gallery stage. pointer-events:none so the
     overlay never eats a tap meant for a tab. */
  .mobile-tabbar::before {
    content: '';
    position: absolute; inset: 0;
    pointer-events: none; z-index: 3;
    background: repeating-linear-gradient(
      to bottom, transparent 0, transparent 2px,
      rgba(0, 0, 0, 0.16) 2px, rgba(0, 0, 0, 0.16) 3px);
    mix-blend-mode: multiply;
  }

  /* Hidden while a sheet is presented, and on scroll-down — the latter
     mirrors tabBarMinimizeBehavior(.onScrollDown), which WabiSabi applies on
     iOS 26. translate rather than display so it animates and so the tab
     order is not disturbed. */
  .mobile-tabbar.is-hidden { transform: translateY(110%); }

  .mtab {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    /* The hover/press plate IS this element's background, so its padding is
       what gives the tint room around the icon and label. At 2px it hugged
       them tightly enough to read as a highlight ON the icon rather than a
       target under it. 6px puts 4px more on every side. */
    padding: 6px 4px;
    background: none; border: 0;
    color: var(--dim, #666);
    font-family: var(--mono, "SF Mono", Menlo, monospace);
    font-size: 0.52rem; letter-spacing: 0.08em; text-transform: uppercase;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: color 220ms ease;
  }
  .mtab.is-active { color: var(--purple, #bd93f9); }
  .mtab:focus-visible { outline: 2px solid var(--purple, #bd93f9); outline-offset: 2px; }

  /* ── Hover and press ────────────────────────────────────────────────
     There was neither, so under a pointer the bar looked dead — the icons
     changed nothing until the tab actually became active. Matches the
     treatment the CTAs use, so the whole surface answers a pointer the same
     way.

     Hover is guarded by `@media (hover: hover)`: mobile browsers leave
     :hover STUCK on the last-tapped element until you tap something else, so
     an unguarded rule leaves a tab looking permanently highlighted after you
     have navigated away from it. :active is what gives a tap its press, and
     it applies everywhere. */
  @media (hover: hover) {
    /* Colour alone was too quiet to read on a 22px stroke icon against a dim
       label — a tinted plate behind the tab is what actually shows which one
       the pointer is on. */
    .mtab:hover { color: var(--purple, #bd93f9); background: rgba(189, 147, 249, 0.10); }
    .mtab:hover .mtab-ico { transform: translateY(-2px); }
  }
  .mtab:active { color: var(--purple, #bd93f9); background: rgba(189, 147, 249, 0.16); }
  .mtab:active .mtab-ico { transform: scale(0.9); }
  /* The transform sits on the ICON, never on the .mtab itself: the label is
     uppercase mono at 0.52rem, and scaling text that small reflows the
     glyphs and makes the whole bar shimmer. */
  .mtab { border-radius: 8px; transition: color 160ms ease, background 160ms ease; }
  .mtab .mtab-ico { transition: transform 140ms ease; }
  /* A selection effect is running on the active icon — its keyframes own the
     transform, and a hover rule fighting them mid-animation makes the effect
     stutter. */
  .mtab[data-fx] .mtab-ico { transition: none; }

  .mtab .mtab-ico {
    width: 22px; height: 22px; display: block;
    transform-origin: 50% 50%;
    will-change: transform, opacity, filter;
  }
  .mtab .mtab-ico svg {
    width: 100%; height: 100%; display: block;
    fill: none; stroke: currentColor; stroke-width: 1.6;
    stroke-linecap: round; stroke-linejoin: round;
  }
  .mtab .mtab-label { white-space: nowrap; }
}

/* ── Effects ─────────────────────────────────────────────────────────────
   Driven by a data attribute rather than a class per effect, so the JS sets
   one value and the CSS owns every timing. `animation` is shorthand, so each
   rule resets any previous effect implicitly — no cleanup pass needed. */

.mtab[data-fx="ignite"]   .mtab-ico { animation: mtab-ignite 640ms ease-out; }
@keyframes mtab-ignite {
  0%   { color: var(--dim, #666); filter: none; transform: scale(1); }
  25%  { color: var(--orange, #ffb86c); filter: drop-shadow(0 0 8px var(--orange, #ffb86c)); transform: scale(1.15); }
  55%  { color: var(--pink, #ff79c6);   filter: drop-shadow(0 0 10px var(--pink, #ff79c6)); transform: scale(1.05); }
  100% { color: var(--purple, #bd93f9); filter: none; transform: scale(1); }
}

.mtab[data-fx="phosphor"] .mtab-ico { animation: mtab-phosphor 460ms ease-out; }
@keyframes mtab-phosphor {
  0%   { filter: brightness(1) drop-shadow(0 0 0 transparent); transform: scale(1); }
  14%  { filter: brightness(5) saturate(0) drop-shadow(0 0 10px #fff); transform: scale(1.1); }
  40%  { filter: brightness(2.4) saturate(0.6) drop-shadow(0 0 16px var(--purple, #bd93f9)); transform: scale(1.04); }
  100% { filter: brightness(1) saturate(1) drop-shadow(0 0 0 transparent); transform: scale(1); }
}

.mtab[data-fx="degauss"]  .mtab-ico { animation: mtab-degauss 560ms steps(12, end); }
@keyframes mtab-degauss {
  0%, 100% { transform: translate(0, 0); filter: none; }
  15% { transform: translate(-2px, 1px); filter: drop-shadow(3px 0 0 var(--red, #ff5555)) drop-shadow(-3px 0 0 var(--cyan, #8be9fd)); }
  35% { transform: translate(3px, -1px); filter: drop-shadow(-3px 0 0 var(--red, #ff5555)) drop-shadow(3px 0 0 var(--cyan, #8be9fd)); }
  55% { transform: translate(-2px, 2px); filter: drop-shadow(2px 1px 0 var(--red, #ff5555)) drop-shadow(-2px -1px 0 var(--cyan, #8be9fd)); }
  78% { transform: translate(2px, 0);   filter: drop-shadow(-2px 0 0 var(--red, #ff5555)) drop-shadow(2px 0 0 var(--cyan, #8be9fd)); }
}

.mtab[data-fx="huedrift"] .mtab-ico { animation: mtab-huedrift 760ms ease-in-out; }
@keyframes mtab-huedrift {
  0%   { color: var(--purple, #bd93f9); filter: none; }
  30%  { color: var(--pink, #ff79c6);   filter: drop-shadow(0 0 6px var(--pink, #ff79c6)); }
  60%  { color: var(--cyan, #8be9fd);   filter: drop-shadow(0 0 6px var(--cyan, #8be9fd)); }
  100% { color: var(--purple, #bd93f9); filter: none; }
}

/* Idle pool — the four quiet ones first. */
.mtab[data-fx="pulse"]   .mtab-ico { animation: mtab-pulse 560ms ease-out; }
@keyframes mtab-pulse {
  0%   { transform: scale(1); opacity: 1; }
  35%  { transform: scale(1.22); opacity: 0.7; }
  70%  { transform: scale(0.96); opacity: 1; }
  100% { transform: scale(1); }
}

.mtab[data-fx="breathe"] .mtab-ico { animation: mtab-breathe 900ms ease-in-out; }
@keyframes mtab-breathe {
  0%   { transform: scale(1); }
  30%  { transform: scale(1.14); }
  65%  { transform: scale(0.98); }
  100% { transform: scale(1); }
}

.mtab[data-fx="blink"]   .mtab-ico { animation: mtab-blink 620ms steps(1, end); }
@keyframes mtab-blink {
  0%, 100% { opacity: 1; }
  18% { opacity: 0.15; } 36% { opacity: 1; }
  54% { opacity: 0.15; } 72% { opacity: 1; }
}

/* …and the three accents, which DO displace the glyph. */
.mtab[data-fx="bounce"]  .mtab-ico { animation: mtab-bounce 520ms cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes mtab-bounce {
  0%   { transform: translateY(0); }
  30%  { transform: translateY(-7px); }
  55%  { transform: translateY(1px); }
  75%  { transform: translateY(-2px); }
  100% { transform: translateY(0); }
}

.mtab[data-fx="wiggle"]  .mtab-ico { animation: mtab-wiggle 480ms ease-in-out; }
@keyframes mtab-wiggle {
  0%, 100% { transform: rotate(0); }
  20% { transform: rotate(-11deg); } 40% { transform: rotate(9deg); }
  60% { transform: rotate(-6deg);  } 80% { transform: rotate(3deg); }
}

/* Rotate is assigned only to radially symmetric glyphs (see the ROTATE_SAFE
   set in mobile-tabbar.js) — on the envelope it reads as upside-down. */
.mtab[data-fx="rotate"]  .mtab-ico { animation: mtab-rotate 620ms cubic-bezier(0.4, 0, 0.2, 1); }
@keyframes mtab-rotate {
  0%   { transform: rotate(0) scale(1); }
  50%  { transform: rotate(180deg) scale(0.86); }
  100% { transform: rotate(360deg) scale(1); }
}

/* First paint only — the two entrance effects. Correct HERE, because the bar
   genuinely has just arrived; wrong in the idle pool, where nothing has. */
.mobile-tabbar.is-entering .mtab:nth-child(odd)  .mtab-ico { animation: mtab-inkbloom 720ms cubic-bezier(0.2, 0.8, 0.3, 1); }
.mobile-tabbar.is-entering .mtab:nth-child(even) .mtab-ico { animation: mtab-settle 700ms cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes mtab-inkbloom {
  0%   { transform: scale(0.72); filter: blur(2.5px) brightness(0.6); opacity: 0.35; }
  45%  { transform: scale(1.1);  filter: blur(0) brightness(1.25);   opacity: 1; }
  100% { transform: scale(1);    filter: none; opacity: 1; }
}
@keyframes mtab-settle {
  0%   { transform: translateY(-9px) scale(1.15); opacity: 0.5; }
  60%  { transform: translateY(2px) scale(0.97);  opacity: 1; }
  100% { transform: translateY(0) scale(1); }
}

/* Motion is decoration here — selection still works, it just does not
   animate, and the idle timer never starts (mobile-tabbar.js). */
@media (prefers-reduced-motion: reduce) {
  .mobile-tabbar, .mobile-tabbar.is-hidden { transition: none; }
  .mtab .mtab-ico { animation: none !important; }
}
