/* ==========================================================================
   KuduDoc — micro-interactions

   A separate layer, loaded after components.css, because tokens.css, base.css
   and components.css are not mine to edit. Nothing here changes a colour, a
   size or a layout: every rule adds a transition to a state that already
   existed and already changed instantly.

   THE TEST EVERY RULE HAD TO PASS. Does the motion tell you something you
   would otherwise have to infer? If it is only decoration, it is not here.
   The whole file is under 20 rules for that reason — a product that animates
   everything is a product where nothing means anything.

   What that ruled out: page-load reveals (the content is why you came),
   hover-lift on cards (a legal document list is not a game menu), bouncing
   anything, and easing longer than 220ms on a control you press hundreds of
   times a day.

   Physical rules: transform and opacity only, so nothing reflows and nothing
   repaints a large layer on a mid-range Android. Everything collapses under
   prefers-reduced-motion.
   ========================================================================== */

/* ---- Press ---------------------------------------------------------------
   The one that matters most, and the one the library was missing. On a
   touchscreen there is no hover, so without a press state the only feedback
   that a tap registered is whatever happens next — and on a slow connection
   that is nothing, for seconds. People tap again. Then they send twice.
   90ms and 0.97 scale: felt, not watched. */
.btn, .app-nav__link, .kd-toast__action, .chip--interactive {
  transition:
    background-color 140ms ease,
    border-color 140ms ease,
    color 140ms ease,
    box-shadow 140ms ease,
    transform 90ms cubic-bezier(.2, .8, .3, 1),
    opacity 160ms ease;
}
.btn:active:not(:disabled) { transform: scale(.97); }

/* Becoming available is a state change worth noticing. The Send button turns
   on the moment a document is ready — the workflow dock exists to explain
   that, and this is the same fact said in half a second. Only the fade in;
   going disabled should not draw the eye to something you can no longer do. */
.btn:disabled { transition: opacity 220ms ease, background-color 220ms ease; }

/* ---- Focus ---------------------------------------------------------------
   Keyboard focus should arrive, not blink. The ring grows from the control's
   own edge so the eye follows it rather than searching for where it landed.
   Never animate focus AWAY: on fast tabbing that leaves a trail of ghosts. */
.btn:focus-visible,
.app-nav__link:focus-visible,
.card--interactive:focus-visible {
  transition: box-shadow 120ms cubic-bezier(.2, .8, .3, 1), outline-color 120ms ease;
}

/* ---- Where you are -------------------------------------------------------
   The nav's active marker slides between items rather than cutting, so a
   click that changes page is visibly the same object moving. Cheap, and it
   makes a 20-item sidebar feel like one control instead of twenty. */
.app-nav__link { position: relative; }
.app-nav__link::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 3px; height: 0;
  border-radius: 0 2px 2px 0;
  background: var(--blue-600);
  transform: translateY(-50%);
  transition: height 180ms cubic-bezier(.2, .8, .3, 1);
}
.app-nav__link.is-active::before { height: 60%; }

/* ---- Rows ----------------------------------------------------------------
   A list row shifts 2px toward the reading direction on hover. Not a lift and
   not a shadow: those say "card you can pick up", and these are lines in a
   ledger. It only has to say "this one, and it is clickable". */
.doc-row, .kd-row, tr[data-href] {
  transition: background-color 130ms ease, transform 130ms cubic-bezier(.2, .8, .3, 1);
}
.doc-row:hover, .kd-row:hover, tr[data-href]:hover { transform: translateX(2px); }

/* ---- Modals --------------------------------------------------------------
   Dialogs scale up very slightly from the centre while the scrim fades. The
   scrim is what actually does the work — it says the page behind is suspended
   — so the panel itself barely moves. 160ms, because a dialog you asked for
   should already be there. */
@keyframes kd-dialog-in { from { opacity: 0; transform: scale(.985) translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes kd-scrim-in  { from { opacity: 0; } to { opacity: 1; } }
dialog[open], .modal[aria-hidden="false"] > *, .kd-modal__panel { animation: kd-dialog-in 160ms cubic-bezier(.2, .8, .3, 1) both; }
dialog::backdrop, .modal__scrim, .kd-modal__scrim { animation: kd-scrim-in 160ms ease both; }

/* ---- Confirmations -------------------------------------------------------
   Copy-to-clipboard and save both replace a label with a tick. Swapping the
   text instantly reads as a glitch; a short scale makes it read as the same
   control reporting back. Add .is-confirmed for ~1.2s, then remove it. */
@keyframes kd-confirm { 0% { transform: scale(.9); opacity: 0; } 55% { transform: scale(1.04); opacity: 1; } 100% { transform: none; opacity: 1; } }
.is-confirmed { animation: kd-confirm 260ms cubic-bezier(.2, .8, .3, 1) both; }

/* ---- Working -------------------------------------------------------------
   A control that is busy dims and stops responding to hover, so "nothing is
   happening" is never mistaken for "my click missed". The spinner is
   deliberately slow: a fast one reads as panic. */
.is-busy { opacity: .65; pointer-events: none; transition: opacity 160ms ease; }
@keyframes kd-spin { to { transform: rotate(360deg); } }
.kd-spinner {
  display: inline-block; width: 14px; height: 14px;
  border: 2px solid var(--ink-200); border-top-color: var(--blue-600);
  border-radius: 50%; animation: kd-spin 900ms linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .btn, .app-nav__link, .kd-toast__action, .chip--interactive,
  .doc-row, .kd-row, tr[data-href], .is-busy { transition: none; }
  .btn:active:not(:disabled),
  .doc-row:hover, .kd-row:hover, tr[data-href]:hover { transform: none; }
  .app-nav__link::before { transition: none; }
  dialog[open], .modal[aria-hidden="false"] > *, .kd-modal__panel,
  dialog::backdrop, .modal__scrim, .kd-modal__scrim,
  .is-confirmed, .kd-spinner { animation: none; }
  /* The spinner still has to READ as working when it cannot turn. */
  .kd-spinner { border-top-color: var(--blue-600); opacity: .7; }
}


/* ---- Minimal chrome -------------------------------------------------------
   Moved here from app.css. It was the ONLY sheet defining the base rule, and
   two pages use the class without loading it: shared-view.html and — worse —
   app/sign.html, the recipient signing view, where the topbar was rendering
   with no flex layout at all. Both already load this file, and all 33 pages
   that load app.css load this one too, so nothing loses the rule by the move.
   Sub-element rules (__link, __filename, __doc) stay in auth.css and sign.css,
   which are the pages that have those elements. */
.minimal-topbar{
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-5) var(--container-pad); border-bottom: var(--border-hairline);
}
