/* ============================================================
   Organiser Plus — LIFE layer (motion, loaders, micro-interactions).
   Loads AFTER orgplus-shell.css. Token-only; no hardcoded colors.
   Premium-restrained: fast (150-300ms), ease-out, calm.
   Everything degrades under prefers-reduced-motion.
   Pair: orgplus-life.js  ·  See PAGE-SPEC.md.
   ============================================================ */

/* ---- 0. ROOT-CAUSE ICON FIX --------------------------------
   DS .alert-medallion is `display:flex; align-items:center` but the
   DS omits justify-content, so its single icon left-packs (~8px off).
   This recurs on every alert/callout/note medallion across all pages.
   One rule centres them all. (Loads after components.css → wins.) */
.alert-medallion,
.callout-medallion,
.nmed {
  justify-content: center;
}
.alert-medallion > svg,
.callout-medallion > svg,
.nmed > svg {
  display: block;
  vertical-align: middle;
  stroke: var(--text-inverse, #fff);
}

/* ============================================================
   0b. HEADER CHROME — DWTC logo lockup (white logomark ‖ product)
   Legacy header carries the DWTC logo image; mockups had text only.
   White logomark (transparent) reads on the navy bar; the landscape
   white asset is opaque-boxed, so logomark is the correct variant.
   ============================================================ */
.ev-brand {
  gap: 13px;
}
.ev-logo {
  height: 32px;
  width: auto;
  display: block;
  flex: none;
}
.ev-brand-sep {
  width: 1px;
  height: 28px;
  background: rgba(255, 255, 255, 0.22);
  flex: none;
  border-radius: 1px;
}
@media (max-width: 860px) {
  .ev-logo {
    height: 26px;
  }
  .ev-brand-sep {
    display: none;
  }
}
/* 5-item legacy nav: keep it from crowding on mid widths */
@media (max-width: 1180px) and (min-width: 861px) {
  .ev-topbar-nav a {
    padding: 8px 10px;
    font-size: 13px;
  }
}

/* ============================================================
   1. MOTION TOKENS  (local, derived from DS scale)
   ============================================================ */
:root {
  --life-ease: cubic-bezier(0.22, 0.9, 0.32, 1); /* ease-out-quint-ish */
  --life-fast: 150ms;
  --life-base: 240ms;
  --life-slow: 360ms;
}

/* ============================================================
   2. ENTRANCE / REVEAL  (transform+opacity only)
   JS adds .is-in when element enters viewport / on load.
   ============================================================ */
[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--life-base) var(--life-ease),
    transform var(--life-base) var(--life-ease);
  will-change: opacity, transform;
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
}
/* staggered children */
[data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity var(--life-base) var(--life-ease),
    transform var(--life-base) var(--life-ease);
}
[data-reveal-stagger].is-in > * {
  opacity: 1;
  transform: none;
}
[data-reveal-stagger].is-in > *:nth-child(1) {
  transition-delay: 40ms;
}
[data-reveal-stagger].is-in > *:nth-child(2) {
  transition-delay: 90ms;
}
[data-reveal-stagger].is-in > *:nth-child(3) {
  transition-delay: 140ms;
}
[data-reveal-stagger].is-in > *:nth-child(4) {
  transition-delay: 190ms;
}
[data-reveal-stagger].is-in > *:nth-child(5) {
  transition-delay: 240ms;
}
[data-reveal-stagger].is-in > *:nth-child(6) {
  transition-delay: 290ms;
}

/* universal on-load entrance — pure CSS, no markup edits, no FOUC.
   @starting-style animates from the start state on first paint;
   unsupported browsers ignore it (content shows normally).
   Scoped :not([data-reveal]) so it never doubles the JS scroll-reveal,
   and excluded inside dialogs (modals manage their own entrance). */
@supports (transition-behavior: allow-discrete) {
  .ev-wrap .ev-panel:not([data-reveal]),
  .ev-wrap .accordion:not([data-reveal]),
  .ev-wrap > .ev-grid:not([data-reveal]) {
    transition:
      opacity var(--life-slow, 360ms) var(--life-ease),
      transform var(--life-slow, 360ms) var(--life-ease);
  }
  @starting-style {
    .ev-wrap .ev-panel:not([data-reveal]),
    .ev-wrap .accordion:not([data-reveal]),
    .ev-wrap > .ev-grid:not([data-reveal]) {
      opacity: 0;
      transform: translateY(14px);
    }
  }
  /* gentle stagger for the first few stacked blocks */
  .ev-wrap .ev-panel:nth-of-type(2) {
    transition-delay: 60ms;
  }
  .ev-wrap .ev-panel:nth-of-type(3) {
    transition-delay: 120ms;
  }
  .ev-wrap .accordion:nth-of-type(2) {
    transition-delay: 60ms;
  }
  .ev-wrap .accordion:nth-of-type(3) {
    transition-delay: 120ms;
  }
}

/* ============================================================
   3. NAVIGATION LOADER  (top progress bar)
   JS shows on same-origin navigation + brief page-enter.
   ============================================================ */
.nav-loader {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 3px;
  z-index: 9999;
  pointer-events: none;
  background: transparent;
  opacity: 0;
  transition: opacity 200ms ease;
}
.nav-loader.is-active {
  opacity: 1;
}
.nav-loader::before {
  content: '';
  display: block;
  height: 100%;
  width: var(--nav-progress, 0%);
  background: linear-gradient(90deg, var(--color-primary, #0d3b72), var(--color-teal, #0c5b6b));
  box-shadow: 0 0 8px var(--color-teal, #0c5b6b);
  transition: width 220ms var(--life-ease);
}

/* ============================================================
   4. SPINNERS / LOADERS
   ============================================================ */
/* generic inline spinner */
.spinner {
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 50%;
  border: 2px solid color-mix(in oklch, currentColor 25%, transparent);
  border-block-start-color: currentColor;
  animation: op-spin 0.7s linear infinite;
}
.spinner-sm {
  width: 14px;
  height: 14px;
  border-width: 2px;
}
.spinner-lg {
  width: 28px;
  height: 28px;
  border-width: 3px;
}

/* button loading state — DS references .btn-loader but doesn't define it */
.btn[aria-busy='true'] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.btn[aria-busy='true'] > * {
  visibility: hidden;
}
.btn[aria-busy='true']::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid color-mix(in oklch, var(--text-inverse, #fff) 35%, transparent);
  border-block-start-color: var(--text-inverse, #fff);
  animation: op-spin 0.65s linear infinite;
}
.btn-ghost[aria-busy='true']::after,
.btn-secondary[aria-busy='true']::after {
  border-color: color-mix(in oklch, var(--text-primary, #0d3b72) 30%, transparent);
  border-block-start-color: var(--text-primary, #0d3b72);
}

/* ============================================================
   5. PROCESS LOADER  (full-screen multi-step overlay)
   For checkout / payment / multi-step handoffs.
   ============================================================ */
.process-loader {
  position: fixed;
  inset: 0;
  z-index: 9998;
  display: grid;
  place-items: center;
  background: color-mix(in oklch, var(--text-primary, #06203f) 55%, transparent);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--life-base) ease,
    visibility var(--life-base);
}
.process-loader.is-active {
  opacity: 1;
  visibility: visible;
}
.process-loader-card {
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xl, 18px);
  box-shadow: var(--shadow-lg, 0 18px 48px rgba(0, 0, 0, 0.28));
  padding: var(--space-6, 28px) var(--space-7, 34px);
  min-width: 280px;
  transform: translateY(10px) scale(0.98);
  transition: transform var(--life-base) var(--life-ease);
}
.process-loader.is-active .process-loader-card {
  transform: none;
}
.process-loader-ring {
  width: 40px;
  height: 40px;
  margin-inline: auto;
  border-radius: 50%;
  border: 3px solid color-mix(in oklch, var(--color-primary, #0d3b72) 18%, transparent);
  border-block-start-color: var(--color-primary, #0d3b72);
  border-inline-end-color: var(--color-teal, #0c5b6b);
  animation: op-spin 0.8s var(--life-ease) infinite;
}
.process-loader-steps {
  list-style: none;
  margin: var(--space-5, 22px) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2_5, 10px);
}
.process-loader-steps li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--text-size-body-sm, 13px);
  color: var(--text-tertiary);
  transition: color var(--life-base);
}
.process-loader-steps li::before {
  content: '';
  width: 16px;
  height: 16px;
  border-radius: 50%;
  flex: none;
  border: 2px solid var(--border-default);
  transition: all var(--life-base) var(--life-ease);
}
.process-loader-steps li.is-active {
  color: var(--text-primary);
  font-weight: 600;
}
.process-loader-steps li.is-active::before {
  border-color: var(--color-primary, #0d3b72);
}
.process-loader-steps li.is-done {
  color: var(--text-secondary);
}
.process-loader-steps li.is-done::before {
  background: var(--color-primary, #0d3b72);
  border-color: var(--color-primary, #0d3b72);
}

/* ============================================================
   6. SKELETON / DATA LOADER  (extends DS .skeleton)
   A table in .is-loading shows shimmering placeholder rows.
   ============================================================ */
.data-table tbody.is-loading td {
  color: transparent !important;
  position: relative;
}
.data-table tbody.is-loading td * {
  visibility: hidden;
}
.data-table tbody.is-loading td::after {
  content: '';
  position: absolute;
  inset-block: 12px;
  inset-inline: 16px 24px;
  border-radius: var(--radius-xs, 4px);
  background: linear-gradient(
    90deg,
    var(--bg-inset, #eef1f5) 0%,
    color-mix(in oklch, var(--bg-inset, #eef1f5) 60%, var(--bg-card, #fff)) 50%,
    var(--bg-inset, #eef1f5) 100%
  );
  background-size: 200% 100%;
  animation: op-shimmer 1.3s ease-in-out infinite;
}

/* ============================================================
   7. MICRO-INTERACTIONS  (hover lift / press / focus polish)
   ============================================================ */
.ev-panel,
.card,
.file-card,
.event-card,
.service-tile {
  transition:
    transform var(--life-fast) var(--life-ease),
    box-shadow var(--life-fast) var(--life-ease),
    border-color var(--life-fast) var(--life-ease);
}
.file-card:hover,
.event-card:hover,
.service-tile:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.1));
  border-color: color-mix(in oklch, var(--color-primary, #0d3b72) 35%, var(--border-default));
}
.btn {
  transition:
    transform var(--life-fast) var(--life-ease),
    box-shadow var(--life-fast) var(--life-ease),
    background-color var(--life-fast) var(--life-ease),
    filter var(--life-fast) var(--life-ease);
}
.btn:not([aria-busy='true']):active {
  transform: translateY(1px) scale(0.985);
}
.btn-primary:hover {
  box-shadow: 0 6px 18px color-mix(in oklch, var(--color-primary, #0d3b72) 32%, transparent);
}
/* interactive table rows */
.data-table tbody tr {
  transition: background-color var(--life-fast) var(--life-ease);
}
.data-table tbody tr:hover {
  background: color-mix(in oklch, var(--color-primary, #0d3b72) 5%, var(--bg-card, #fff));
}

/* alert/medallion gentle pop on insert (toasts handled by DS) */
.alert[data-reveal].is-in .alert-medallion {
  animation: op-pop var(--life-slow) var(--life-ease) both;
}

/* ============================================================
   7b. EMPTY STATE  (no-data placeholder for lists/tables)
   ============================================================ */
.empty-state {
  text-align: center;
  padding: clamp(32px, 6vw, 56px) var(--space-5, 20px);
}
.empty-state-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  margin-inline: auto;
  display: grid;
  place-items: center;
  background: var(--bg-inset, #eef1f5);
  color: var(--text-tertiary);
  box-shadow: inset 0 0 0 1px var(--border-default);
}
.empty-state-icon > svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}
.empty-state-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 14px 0 4px;
}
.empty-state-text {
  font-size: 13.5px;
  color: var(--text-tertiary);
  max-width: 42ch;
  margin: 0 auto 16px;
  line-height: 1.5;
}

/* ============================================================
   7c. INLINE FORM VALIDATION MOTION
   shake on error · slide-in message · async validating spinner
   ============================================================ */
.input.is-shaking,
.textarea.is-shaking,
.select.is-shaking {
  animation: op-shake 0.4s var(--life-ease) both;
}
.field-error-msg {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--error-text);
  font-size: var(--text-size-caption, 12px);
  margin-block-start: var(--space-1_5, 6px);
  animation: op-slide-down var(--life-base) var(--life-ease) both;
}
.field-error-msg > svg {
  width: 13px;
  height: 13px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
/* async validating: spinner pinned inside the field */
.field-validating {
  position: relative;
}
.field-validating .input {
  padding-inline-end: 38px;
}
.field-validating::after {
  content: '';
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: 12px;
  width: 15px;
  height: 15px;
  margin-block-start: -7px;
  border-radius: 50%;
  border: 2px solid color-mix(in oklch, var(--text-tertiary) 30%, transparent);
  border-block-start-color: var(--color-primary, #0d3b72);
  animation: op-spin 0.65s linear infinite;
}

/* ============================================================
   7d. KEY-VALUE DETAIL BLOCKS  (label/value "spec sheets")
   Mockups use bare <dt>/<dd> in .kv-row, but DS only styles
   .kv-label/.kv-value — so labels rendered unstyled (flat, grey,
   no hierarchy). This styles the bare elements into an aligned
   2-column grid with a clear label→value hierarchy, groups runs
   into a card, and color-codes status values. Cascades site-wide.
   Rows with an inline style (totals, warning lines) are left alone.
   ============================================================ */
.kv-row {
  display: grid;
  grid-template-columns: minmax(120px, 210px) 1fr;
  gap: var(--space-1) var(--space-5, 22px);
  align-items: baseline;
  padding: var(--space-2_5, 10px) 0;
  border-bottom: 1px solid var(--border-subtle, #eef1f5);
}
.kv-row:not([style*='color']) > dt {
  margin: 0;
  font-size: var(--text-size-caption, 12px);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.45;
}
.kv-row:not([style*='color']) > dd {
  margin: 0;
  font-size: var(--text-size-body-sm, 14px);
  font-weight: 600;
  color: var(--text-primary);
  word-break: break-word;
  line-height: 1.45;
}
.kv-row:not([style*='color']) > dd:empty::after {
  content: '—';
  color: var(--text-tertiary);
  font-weight: 400;
}

/* grouped card (JS wraps consecutive .kv-row runs in .kv-list) */
.kv-list {
  border: 1px solid var(--border-subtle, #eef1f5);
  border-radius: var(--radius-lg, 12px);
  background: color-mix(in oklch, var(--bg-inset, #f4f6f9) 35%, var(--bg-card, #fff));
  padding: var(--space-1) var(--space-4, 18px);
  overflow: hidden;
}
.kv-list > .kv-row {
  transition: background var(--life-fast) var(--life-ease);
}
.kv-list > .kv-row:last-child {
  border-bottom: none;
}
.kv-list > .kv-row:hover {
  background: color-mix(in oklch, var(--color-primary, #0d3b72) 4%, transparent);
}

/* color-coded value pill (added by OrgPlus.enhanceDetails) */
.kv-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px;
  border-radius: var(--radius-pill, 999px);
  font-size: var(--text-size-caption, 12px);
  font-weight: 700;
  line-height: 1.5;
}
.kv-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.kv-pill-success {
  color: var(--success-text);
  background: var(--success-bg);
}
.kv-pill-warning {
  color: var(--warning-text);
  background: var(--warning-bg);
}
.kv-pill-danger {
  color: var(--error-text);
  background: var(--error-bg);
}
.kv-pill-info {
  color: var(--info-text);
  background: var(--info-bg);
}
.kv-pill-neutral {
  color: var(--text-secondary);
  background: var(--bg-inset, #f4f6f9);
}
.kv-num {
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  .kv-row {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .kv-row:not([style]) > dt {
    font-size: 11px;
  }
}

/* ============================================================
   8. KEYFRAMES
   ============================================================ */
@keyframes op-shake {
  10%,
  90% {
    transform: translateX(-1px);
  }
  20%,
  80% {
    transform: translateX(2px);
  }
  30%,
  50%,
  70% {
    transform: translateX(-4px);
  }
  40%,
  60% {
    transform: translateX(4px);
  }
}
@keyframes op-slide-down {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes op-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes op-shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}
@keyframes op-pop {
  0% {
    transform: scale(0.6);
    opacity: 0;
  }
  60% {
    transform: scale(1.08);
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

/* ============================================================
   9. REDUCED MOTION  (disable all movement, keep states)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .spinner,
  .btn[aria-busy='true']::after,
  .process-loader-ring,
  .data-table tbody.is-loading td::after,
  .alert .alert-medallion {
    animation-duration: 0.01ms !important;
  }
  .nav-loader::before {
    transition: none;
  }
  *,
  .btn,
  .file-card,
  .ev-panel {
    transition-duration: 0.01ms !important;
  }
}
