/* INCHUB 360 Hub Motion: the Living Hub.
   Brand rule (approved 2026-10-14): the Hub mark is alive. It turns whenever INCHUB is working
   (the only loading indicator), and it reacts to the customer: clicks, steps, scrolling, success, errors.
   Colors inherit from tokens (--ih-*), with brand fallbacks. */

ih-hub {
  --ih-hub-size: 32px;
  --ih-hub-leaf: currentColor;
  --ih-hub-accent: var(--ih-color-brand-orange, #FF5A1F);
  --ih-hub-off: color-mix(in srgb, currentColor 30%, transparent); /* unlit leaves stay visible: the mark always reads as complete */
  --ih-hub-quarter: 350ms;              /* one 90° turn */
  display: inline-grid;
  place-items: center;
  inline-size: var(--ih-hub-size);
  block-size: var(--ih-hub-size);
  color: var(--ih-text, #1A1410);
  vertical-align: middle;
  flex: none;
}
ih-hub[tone="paper"]  { color: var(--ih-color-brand-paper, #FAF7F2); }
ih-hub[tone="on-orange"] { color: var(--ih-color-brand-ink, #1A1410); --ih-hub-accent: var(--ih-color-brand-paper, #FAF7F2); }
/* On an orange surface the accent leaf would vanish: any container marked data-on-orange switches it to paper (approved app-icon colours). */
[data-on-orange] ih-hub { --ih-hub-accent: var(--ih-color-brand-paper, #FAF7F2); }
ih-hub[tone="mono"]   { --ih-hub-accent: currentColor; }

ih-hub svg { inline-size: 100%; block-size: 100%; overflow: visible; }
ih-hub .ih-hub__turn,
ih-hub .ih-hub__react,
ih-hub .ih-hub__scroll { transform-box: view-box; transform-origin: 60px 60px; }
/* Layers: scroll (follows page scroll) > react (tick, nudge, error) > turn (state: spin, progress, reveal) */
ih-hub .ih-hub__scroll { transform: rotate(var(--ih-hub-scroll, 0deg)); }
ih-hub .ih-hub__react { transition: transform 260ms cubic-bezier(.34,1.5,.64,1); }
ih-hub .ih-hub__leaf { fill: var(--ih-hub-leaf); transform-box: view-box; transform-origin: 60px 60px; transition: fill 240ms ease; }
ih-hub .ih-hub__leaf[data-k="3"] { fill: var(--ih-hub-accent); }
ih-hub .ih-hub__dot  { fill: var(--ih-hub-accent); transform-box: view-box; transform-origin: 60px 60px; }
ih-hub .ih-hub__sr { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* 1. SPIN: indeterminate wait (page loads, fetches, buttons). Quarter-turn "ticks". */
ih-hub[state="spin"] .ih-hub__turn { animation: ih-hub-spin calc(var(--ih-hub-quarter) * 4) infinite; }
@keyframes ih-hub-spin {
  0%   { transform: rotate(0deg);   animation-timing-function: cubic-bezier(.6,0,.3,1); }
  25%  { transform: rotate(90deg);  animation-timing-function: cubic-bezier(.6,0,.3,1); }
  50%  { transform: rotate(180deg); animation-timing-function: cubic-bezier(.6,0,.3,1); }
  75%  { transform: rotate(270deg); animation-timing-function: cubic-bezier(.6,0,.3,1); }
  100% { transform: rotate(360deg); }
}

/* 2. REVEAL: app launch / first load. Leaves turn in, hub dot lands. Then switch to spin. */
ih-hub[state="reveal"] .ih-hub__turn { animation: ih-hub-reveal-turn 900ms cubic-bezier(.16,1,.3,1) both; }
ih-hub[state="reveal"] .ih-hub__leaf { animation: ih-hub-leaf-in 620ms cubic-bezier(.34,1.4,.64,1) both; animation-delay: calc(var(--k) * 90ms); }
ih-hub[state="reveal"] .ih-hub__dot  { animation: ih-hub-dot-in 420ms cubic-bezier(.34,1.8,.64,1) 520ms both; }
@keyframes ih-hub-reveal-turn { from { transform: rotate(-180deg); } to { transform: rotate(0deg); } }
@keyframes ih-hub-leaf-in { from { transform: rotate(-60deg) scale(0); } to { transform: rotate(0) scale(1); } }
@keyframes ih-hub-dot-in { from { transform: scale(0); } to { transform: scale(1); } }

/* 3. PROGRESS: determinate (order steps, uploads). value 0..4 = leaves lit; the fan turns 90° per step. */
ih-hub[state="progress"] .ih-hub__leaf { fill: var(--ih-hub-off); }
ih-hub[state="progress"] .ih-hub__turn { transition: transform 520ms cubic-bezier(.6,0,.3,1); transform: rotate(calc(var(--ih-hub-step, 0) * 90deg)); }
ih-hub[state="progress"] .ih-hub__leaf.is-on { fill: var(--ih-hub-leaf); }
ih-hub[state="progress"] .ih-hub__leaf.is-on[data-k="3"] { fill: var(--ih-hub-accent); }

/* 4. DONE: success settle. Dot pulses once. */
ih-hub[state="done"] .ih-hub__dot { animation: ih-hub-pulse 700ms cubic-bezier(.34,1.6,.64,1) both; }
@keyframes ih-hub-pulse { 0% { transform: scale(1); } 45% { transform: scale(2.1); } 100% { transform: scale(1); } }

/* 4b. IDLE (owner rule 2026-10-15: the mark is never frozen). At rest it turns slowly and continuously;
   the header logo turns slower and still follows scroll and hover on its own layers. */
ih-hub[state="idle"] .ih-hub__turn, ih-hub[state="done"] .ih-hub__turn { animation: ih-hub-idle 24s linear infinite; }
ih-hub[main][state="idle"] .ih-hub__turn { animation-duration: 40s; }
@keyframes ih-hub-idle { to { transform: rotate(360deg); } }

/* 5. REACTIONS (the logo answers the customer) */
/* tick: a quarter turn on click, navigation, or a completed action */
ih-hub.is-tick .ih-hub__react { animation: ih-hub-tick 420ms cubic-bezier(.6,0,.3,1); }
@keyframes ih-hub-tick { from { transform: rotate(-90deg); } to { transform: rotate(0deg); } }
/* nudge: hover/focus on the logo or on a link that contains it */
:is(a, button, [data-hub-host]):is(:hover, :focus-visible) ih-hub:not([state="spin"]) .ih-hub__react,
ih-hub[data-hub-host]:hover .ih-hub__react { transform: rotate(22deg); }
/* error: leaves shake and the hub dot turns crimson briefly */
ih-hub.is-error .ih-hub__react { animation: ih-hub-shake 460ms ease; }
ih-hub.is-error .ih-hub__dot { fill: var(--ih-danger, #BE123C); transition: fill 120ms; }
@keyframes ih-hub-shake { 0%,100% { transform: rotate(0); } 20% { transform: rotate(-14deg); } 40% { transform: rotate(11deg); } 60% { transform: rotate(-7deg); } 80% { transform: rotate(4deg); } }

/* Reduced motion: no rotation. Spin becomes a gentle hub-dot breath; reveal becomes a fade. */
@media (prefers-reduced-motion: reduce) {
  ih-hub[state="spin"] .ih-hub__turn { animation: none; }
  ih-hub[state="spin"] .ih-hub__dot { animation: ih-hub-breathe 1.4s ease-in-out infinite; }
  ih-hub[state="reveal"] .ih-hub__turn, ih-hub[state="reveal"] .ih-hub__leaf, ih-hub[state="reveal"] .ih-hub__dot { animation: ih-hub-fade 300ms ease both; }
  ih-hub[state="progress"] .ih-hub__turn { transition: none; }
  ih-hub[state="idle"] .ih-hub__turn, ih-hub[state="done"] .ih-hub__turn { animation: none; }
  ih-hub[state="done"] .ih-hub__dot { animation: none; }
  ih-hub .ih-hub__scroll { transform: none; }
  ih-hub.is-tick .ih-hub__react, ih-hub.is-error .ih-hub__react { animation: none; }
  :is(a, button, [data-hub-host]):is(:hover, :focus-visible) ih-hub .ih-hub__react { transform: none; }
  @keyframes ih-hub-breathe { 50% { opacity: .35; } }
  @keyframes ih-hub-fade { from { opacity: 0; } }
}

/* Page / route transition overlay. Appears only after 300 ms, so fast loads never flash. */
.ih-loading-overlay {
  position: fixed; inset: 0; z-index: 1000;
  display: grid; place-items: center; align-content: center; gap: 14px;
  background: color-mix(in srgb, var(--ih-bg, #FAF7F2) 86%, transparent);
  backdrop-filter: blur(2px);
  animation: ih-overlay-in 200ms ease 300ms both;
  font-family: var(--ih-font-family-brand, Manrope, system-ui, sans-serif);
  color: var(--ih-text-muted, #62594E); font-size: 14px;
}
.ih-loading-overlay ih-hub { --ih-hub-size: 56px; }
@keyframes ih-overlay-in { from { opacity: 0; } to { opacity: 1; } }

/* Splash: app launch and first website load */
.ih-splash {
  position: fixed; inset: 0; z-index: 1001; display: grid; place-items: center;
  background: var(--ih-color-brand-orange, #FF5A1F);
  transition: opacity 260ms ease;
}
.ih-splash ih-hub { --ih-hub-size: 96px; }
.ih-splash.is-leaving { opacity: 0; pointer-events: none; }

/* Hub inside a button: the fan turns where the customer just clicked */
.ih-btn-hub { --ih-hub-size: 18px; flex: none; margin-inline-end: 2px; }
.is-busy { cursor: progress; }
