/* ═══════════════════════════════════════════════════════════════════════
   TRIAKAR ADDITIVE MOTION SYSTEM  ·  admin-motion.css
   Admin Panel and Business OS only. Loaded after motion.css, which
   supplies the curves and durations.
   ═══════════════════════════════════════════════════════════════════════

   The admin panels are a different job from the storefront and get a
   different dialect of the same language. Someone in here is reading
   numbers and typing, forty times an hour, so:

     · nothing scroll reveals. A ledger row that fades in as you scroll
       past it is a ledger row you cannot read.
     · durations are one step faster than the storefront across the
       board. 110 to 230ms, never 500.
     · rows and cells never move. Only their surface changes.
     · motion is used to answer questions the operator actually has:
       did that save, which tab am I on, is this number fresh, is that
       table still loading.

   Everything here is transform, opacity or filter. Nothing animates a
   layout property, because these tables can carry several hundred rows.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
   1 · PANEL SWITCHING
   .panel toggles display, so the animation fires on activation with no
   JS involved. Short, because tab switching is a navigation, not a
   reveal, and it happens constantly.
   ═══════════════════════════════════════════════════════════════════════ */

@keyframes m-panel-in{
  0%   { opacity: 0; transform: translate3d(0, 6px, 0) }
  100% { opacity: 1; transform: translate3d(0, 0, 0) }
}
.panel.active{
  animation: m-panel-in var(--m-t-2) var(--m-e-deposit) both;
}

/* The sidebar tab lays a layer on its leading edge instead of just
   turning orange, so the active row is findable at a glance without
   reading it. */
.tab{
  position: relative;
  transition: background-color var(--m-t-0) var(--m-e-gantry),
              color var(--m-t-0) var(--m-e-gantry);
}
.tab::before{
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--tri-orange, #C4622A);
  transform: scaleY(0);
  transform-origin: center top;
  transition: transform var(--m-t-1) var(--m-e-gantry);
  pointer-events: none;
}
.tab.active::before{ transform: scaleY(1) }
.tab:active{ transform: translate3d(1px, 0, 0); transition-duration: 80ms }

.tab-icon{ transition: transform var(--m-t-1) var(--m-e-release) }
.tab.active .tab-icon{ transform: scale(1.12) }

/* ═══════════════════════════════════════════════════════════════════════
   2 · TABLES
   Rows settle as they are inserted. This is a genuine signal, not
   decoration: it tells the operator the table just re-fetched. Only the
   first rows animate, so a 400 row ledger does not turn into a wave.
   ═══════════════════════════════════════════════════════════════════════ */

@keyframes m-row-settle{
  0%   { opacity: 0; transform: translate3d(0, 4px, 0) }
  100% { opacity: 1; transform: translate3d(0, 0, 0) }
}
.tbl-wrap tbody tr:nth-child(-n+14){
  animation: m-row-settle 200ms var(--m-e-deposit) both;
}
.tbl-wrap tbody tr:nth-child(1){ animation-delay: 0ms }
.tbl-wrap tbody tr:nth-child(2){ animation-delay: 14ms }
.tbl-wrap tbody tr:nth-child(3){ animation-delay: 28ms }
.tbl-wrap tbody tr:nth-child(4){ animation-delay: 42ms }
.tbl-wrap tbody tr:nth-child(5){ animation-delay: 56ms }
.tbl-wrap tbody tr:nth-child(6){ animation-delay: 70ms }
.tbl-wrap tbody tr:nth-child(7){ animation-delay: 84ms }
.tbl-wrap tbody tr:nth-child(8){ animation-delay: 98ms }
.tbl-wrap tbody tr:nth-child(n+9){ animation-delay: 108ms }

/* Rows tint, they never lift. A moving row under a cursor makes a table
   impossible to scan. */
.tbl-wrap tbody tr{
  transition: background-color var(--m-t-0) var(--m-e-gantry);
}

/* A row that was just written to holds a brief warm wash, so the operator
   can see which line their save landed on. Added by JS as .m-fresh. */
@keyframes m-row-fresh{
  0%   { background-color: rgba(196, 98, 42, .18) }
  100% { background-color: rgba(196, 98, 42, 0) }
}
.m-fresh{ animation: m-row-fresh 1.1s var(--m-e-glass) both }

/* ═══════════════════════════════════════════════════════════════════════
   3 · KPI TILES
   The tile itself is static. Only the number reacts, and only when it
   actually changes.
   ═══════════════════════════════════════════════════════════════════════ */

.kpi{
  transition: box-shadow var(--m-t-2) var(--m-e-glass),
              border-color var(--m-t-2) var(--m-e-glass);
}
.kpi:hover{ transform: none }   /* the 1px lift is removed on purpose */

@keyframes m-val-tick{
  0%   { transform: translate3d(0, 3px, 0) scale(.98); opacity: .35;
         filter: drop-shadow(0 3px 0 rgba(196, 98, 42, .45)) }
  100% { transform: translate3d(0, 0, 0) scale(1); opacity: 1;
         filter: drop-shadow(0 0 0 rgba(196, 98, 42, 0)) }
}
.kpi-val.m-tick, .val.m-tick, .m-tick{
  animation: m-val-tick var(--m-t-2) var(--m-e-cool) both;
}

.chart-box{ animation: m-panel-in var(--m-t-3) var(--m-e-deposit) both }

/* ═══════════════════════════════════════════════════════════════════════
   4 · CONTROLS
   Faster than the storefront, and the press is the whole feedback: an
   admin button does not need a hover bloom to feel expensive.
   ═══════════════════════════════════════════════════════════════════════ */

.btn, .btn-sm, .btn-ghost, .btn-primary, .btn-danger, .btn-icon-tint, .btn-icon-muted{
  transition: background-color var(--m-t-0) var(--m-e-press),
              border-color var(--m-t-0) var(--m-e-press),
              color var(--m-t-0) var(--m-e-press),
              box-shadow var(--m-t-1) var(--m-e-glass),
              transform 90ms var(--m-e-press);
}
.btn:active, .btn-sm:active, .btn-ghost:active,
.btn-primary:active, .btn-danger:active,
.btn-icon-tint:active, .btn-icon-muted:active{
  transform: scale3d(1.01, .94, 1);
}

/* A destructive button is the one control that should feel different
   under the finger: it resists slightly, then gives. */
.btn-danger:active{ transform: scale3d(1, .9, 1); transition-duration: 130ms }

.qchip{
  transition: background-color var(--m-t-0) var(--m-e-gantry),
              border-color var(--m-t-0) var(--m-e-gantry),
              color var(--m-t-0) var(--m-e-gantry),
              transform var(--m-t-0) var(--m-e-gantry);
}
.qchip:active{ transform: scale(.95) }

/* Fields: the frame reacts, the field never moves, and an invalid field
   uses the shared gantry shudder from motion.css (.m-reject). */
.form-group input, .form-group select, .form-group textarea{
  transition: border-color var(--m-t-1) var(--m-e-glass),
              box-shadow var(--m-t-1) var(--m-e-glass),
              background-color var(--m-t-1) var(--m-e-glass);
}

/* ═══════════════════════════════════════════════════════════════════════
   5 · DIALOGS
   js/admin-dialog.js appends .biz-dlg-ov with .biz-dlg inside it and had
   no motion at all, so confirmations used to appear as a hard cut. The
   animation fires on insertion; no change to that file is needed.
   ═══════════════════════════════════════════════════════════════════════ */

@keyframes m-dlg-scrim{ from{ opacity: 0 } to{ opacity: 1 } }
.biz-dlg-ov{ animation: m-dlg-scrim var(--m-t-1) var(--m-e-glass) both }

@keyframes m-dlg-in{
  0%   { opacity: 0; transform: translate3d(0, 10px, 0) scale(.97) }
  100% { opacity: 1; transform: translate3d(0, 0, 0) scale(1) }
}
.biz-dlg{
  animation: m-dlg-in var(--m-t-3) var(--m-e-cool) both;
  will-change: transform, opacity;
}

/* A dialog asking for something destructive arrives without the friendly
   overshoot. It lands flat. */
.biz-dlg:has(.biz-dlg-btn-danger){
  animation-timing-function: var(--m-e-press);
  animation-duration: var(--m-t-2);
}

/* ═══════════════════════════════════════════════════════════════════════
   6 · LOADING
   The admin skeletons keep their own greys, they only change direction:
   bottom up, matching every other build on the site.
   ═══════════════════════════════════════════════════════════════════════ */

@keyframes m-admin-sweep{
  0%   { background-position: 50% 130% }
  100% { background-position: 50% -30% }
}
.skel-bar{
  background: linear-gradient(
    180deg,
    var(--surface-3, #EFEAE0) 0%,
    var(--surface-2, #F6F3EC) 40%,
    rgba(196, 98, 42, .10) 50%,
    var(--surface-2, #F6F3EC) 60%,
    var(--surface-3, #EFEAE0) 100%
  ) !important;
  background-size: 100% 300% !important;
  animation: m-admin-sweep 1.4s var(--m-e-glass) infinite !important;
}

/* Saving state on a button: the label dims and the layer stack runs.
   Markup comes from TAMotion.loader('sm'). */
.btn.m-busy{ pointer-events: none; opacity: .72 }
.btn.m-busy .m-loader-sm > i{ background: currentColor }

/* Admin toasts. The Business OS stack collapses its own height on exit,
   which is a layout transition and is left exactly as it was, because
   replacing it would change how the stack reflows. Only the curves it
   uses for opacity and transform are brought onto the system. */
.toast-item{
  transition: opacity var(--m-t-2) linear,
              transform var(--m-t-3) var(--m-e-cool),
              max-height 250ms var(--m-e-retract) 50ms,
              margin-top 250ms var(--m-e-retract) 50ms,
              padding 250ms var(--m-e-retract) 50ms !important;
}
/* Admin Panel's single toast sits bottom right and now arrives from the
   bottom edge like the storefront one, so the two panels agree. */
.toast{
  transition: transform var(--m-t-3) var(--m-e-cool),
              opacity var(--m-t-2) linear !important;
}

/* ═══════════════════════════════════════════════════════════════════════
   7 · REDUCED MOTION
   ═══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce){
  .panel.active, .chart-box, .tbl-wrap tbody tr,
  .biz-dlg, .biz-dlg-ov, .kpi-val.m-tick, .val.m-tick, .m-tick, .m-fresh{
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .skel-bar{ animation: none !important }
  .tab::before{ transition: none !important }
}
