/* ==========================================================================
   BGFP Client Portal - the shared "feel" layer (motion, depth, polish).

   Loaded AFTER tailwind.css. Behaviour lives in static/js/motion.js; the
   head script static/js/theme-init.js adds html.js-motion (and, ~1.2 s later,
   html.m-settled). Design principles, borrowed from the firm's internal
   dashboard guide but toned down for a client-facing site:

   1. Content is never hidden by motion. Anything that starts hidden/moved is
      gated by html.js-motion, so if JavaScript fails nothing is ever hidden.
   2. Entrances play once per real page load. html.m-settled turns every
      entrance keyframe off ~1.2 s after load (and on back/forward-cache
      restores), so an HTMX swap or a Back navigation never replays them.
   3. Animate only transform, opacity, colour and shadow. Never layout.
   4. Light AND dark are first-class (dark = class "dark" on <html>, NOT the
      OS setting). Every colour below is a token with a .dark override.
   5. Restraint is the brand: gold is the firm's signature and appears only as
      a hairline or a thin bar. No pulsing dots, ripples, parallax or confetti.
   6. prefers-reduced-motion: reduce switches everything off (kill-switch at
      the END of this file; motion.js also checks).

   CSP: style-src 'self' only. Everything here is a plain stylesheet; JS only
   uses the CSSOM (el.style.x = ...), never style="" attributes.

   LAYERS: Tailwind's utilities live in @layer utilities, and any UNLAYERED
   rule beats every layered rule regardless of specificity. So:
     - "default look" rules (.m-card surface, .m-empty, .m-dropzone idle, ...)
       are in @layer components: a Tailwind utility on the same element
       (border-amber-200, rounded-lg, bg-slate-50, flex, ...) still wins.
     - hover/active/focus/state rules and animations are unlayered on purpose,
       so they win over a utility's resting value (e.g. a card's hover border).
   NEVER put a var() that may resolve to 'none' inside a box-shadow list: it
   invalidates the whole declaration (a real bug in the dashboard's dark mode).
   Every shadow token below is a real shadow in both themes.
   ========================================================================== */


/* ---- Tokens --------------------------------------------------------------- */
:root {
  --m-ease: cubic-bezier(.22, .8, .3, 1);
  --m-fast: 140ms;
  --m-med: 220ms;
  --m-enter: 260ms;
  --m-step: 35ms;

  /* Firm gold (accent-500 / accent-600): signature hairlines only. */
  --m-gold: #b08d57;
  --m-gold-deep: #96723f;
  --m-gold-ring: rgb(176 141 87 / .26);

  /* Surfaces */
  --m-surface: #ffffff;
  --m-border: #e2e8f0;
  --m-border-hover: #9fb3c8;
  --m-text-muted: #64748b;      /* 4.7:1 on white */
  --m-icon-muted: #829ab1;      /* decorative icons only */

  /* Depth: soft, navy-tinted shadows (never pure black in light mode). */
  --m-shadow-card: 0 1px 2px rgb(15 23 42 / .05), 0 1px 3px rgb(15 23 42 / .06);
  --m-shadow-btn: 0 2px 6px -1px rgb(15 23 42 / .16);
  --m-lift: 0 12px 26px -10px rgb(16 42 67 / .24), 0 3px 8px -2px rgb(16 42 67 / .09);
  --m-topbar-shadow: 0 8px 18px -10px rgb(15 23 42 / .24);

  /* Rows: --m-row is an alpha tint (works over any background);
     --m-row-solid is the same tint pre-blended, for sticky cells. */
  --m-row: rgb(16 42 67 / .045);
  --m-row-solid: #f4f6f8;

  /* Focus halo */
  --m-ring: rgb(98 125 152 / .38);

  /* Skeleton: tinted base (white is invisible on a white card) + sweep. */
  --m-skel: #e9eef3;
  --m-shimmer: rgb(255 255 255 / .75);

  /* Dropzone */
  --m-dz-border: #cbd5e1;
  --m-dz-bg: #f8fafc;
  --m-dz-border-hover: #829ab1;
  --m-dz-bg-hover: #f0f4f8;
  --m-dz-bg-active: rgb(176 141 87 / .09);
  --m-ok-tint: rgb(16 185 129 / .14);
}

:root.dark {
  --m-gold-deep: #96723f;
  --m-surface: #0f172a;
  --m-border: #334155;
  --m-border-hover: #627d98;
  --m-text-muted: #94a3b8;
  --m-icon-muted: #64748b;

  --m-shadow-card: 0 1px 2px rgb(0 0 0 / .4), 0 1px 3px rgb(0 0 0 / .3);
  --m-shadow-btn: 0 3px 8px -1px rgb(0 0 0 / .5);
  --m-lift: 0 14px 28px -10px rgb(0 0 0 / .65), 0 3px 8px -2px rgb(0 0 0 / .4);
  --m-topbar-shadow: 0 8px 18px -10px rgb(0 0 0 / .7);

  --m-row: rgb(159 179 200 / .07);
  --m-row-solid: #192235;

  --m-ring: rgb(159 179 200 / .42);

  --m-skel: #1e293b;
  --m-shimmer: rgb(148 163 184 / .14);

  --m-dz-border: #475569;
  --m-dz-bg: #0f172a;
  --m-dz-border-hover: #627d98;
  --m-dz-bg-hover: #162033;
  --m-dz-bg-active: rgb(176 141 87 / .12);
  --m-ok-tint: rgb(52 211 153 / .16);
  --m-gold-ring: rgb(176 141 87 / .32);
}


/* ---- Keyframes ------------------------------------------------------------- */
@keyframes m-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-rise-sm {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes m-drop {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes m-grow-y {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes m-halo {
  from { box-shadow: 0 0 0 0 var(--m-ring); }
  to   { box-shadow: 0 0 0 6px rgb(0 0 0 / 0); }
}
@keyframes m-spin {
  to { transform: rotate(360deg); }
}
@keyframes m-shimmer {
  to { transform: translateX(100%); }
}


/* ---- Page entrance ----------------------------------------------------------
   Automatic for the direct children of "main > div" (the content wrapper in
   base.html), and for the children of any element carrying data-stagger.
   The stagger index (--i) is plain CSS (nth-child) rather than JS: JS-set
   indexes arrive after first paint and would restart the delays (a flash).
   Cap: 6 blocks for the page, 9 for data-stagger. */
main > div > * { --i: 5; }
main > div > :nth-child(1) { --i: 0; }
main > div > :nth-child(2) { --i: 1; }
main > div > :nth-child(3) { --i: 2; }
main > div > :nth-child(4) { --i: 3; }
main > div > :nth-child(5) { --i: 4; }

[data-stagger] > * { --i: 8; }
[data-stagger] > :nth-child(1) { --i: 0; }
[data-stagger] > :nth-child(2) { --i: 1; }
[data-stagger] > :nth-child(3) { --i: 2; }
[data-stagger] > :nth-child(4) { --i: 3; }
[data-stagger] > :nth-child(5) { --i: 4; }
[data-stagger] > :nth-child(6) { --i: 5; }
[data-stagger] > :nth-child(7) { --i: 6; }
[data-stagger] > :nth-child(8) { --i: 7; }

html.js-motion:not(.m-settled) main > div > *,
html.js-motion:not(.m-settled) [data-stagger] > * {
  animation: m-rise var(--m-enter) var(--m-ease) backwards;
  animation-delay: calc(var(--i, 5) * var(--m-step));
}
/* A modal overlay is position:fixed: only fade it (a translate would shift the backdrop). */
html.js-motion:not(.m-settled) main > div > [role="dialog"] {
  animation: m-fade var(--m-enter) var(--m-ease) backwards;
}

/* Page title: a thin gold hairline under the <h1> draws in. Absolutely
   positioned so it never changes the page layout. */
.m-title { position: relative; }
.m-title::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -.42rem;
  width: 2.5rem;
  height: 2px;
  border-radius: 2px;
  background: var(--m-gold);
  transform-origin: left center;
  pointer-events: none;
}
html.js-motion:not(.m-settled) .m-title::after {
  animation: m-draw 520ms var(--m-ease) 200ms backwards;
}

/* Anchor jumps (#action-items ...) must clear the sticky top bar. */
main [id] { scroll-margin-top: 4.75rem; }
.m-scroll { scroll-behavior: smooth; scroll-padding-top: 4.75rem; }


/* ---- Selection --------------------------------------------------------------- */
::selection { background: rgb(176 141 87 / .3); }


/* ---- Top bar -----------------------------------------------------------------
   Sticky inside the scrolling column (div.m-scroll). motion.js toggles
   .is-scrolled once the column has scrolled a few pixels. */
.m-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  transition: box-shadow var(--m-med) ease;
}
.m-topbar.is-scrolled { box-shadow: var(--m-topbar-shadow); }


/* ---- Cards ---------------------------------------------------------------------- */
@layer components {
  .m-card {
    background-color: var(--m-surface);
    border: 1px solid var(--m-border);
    border-radius: .75rem;
    box-shadow: var(--m-shadow-card);
  }
  /* A tile that is a link/button: needs a box for transform to apply to. */
  .m-card-link { display: block; }
}
.m-card-link {
  cursor: pointer;
  transition:
    transform var(--m-med) var(--m-ease),
    box-shadow var(--m-med) var(--m-ease),
    border-color var(--m-fast) ease,
    background-color var(--m-fast) ease;
}
@media (hover: hover) {
  .m-card-link:hover {
    transform: translateY(-2px);
    border-color: var(--m-border-hover);
    box-shadow: var(--m-lift);
  }
}
.m-card-link:active {
  transform: translateY(-1px) scale(.99);
  box-shadow: var(--m-shadow-card);
}
.m-card-link:focus-visible {
  border-color: var(--m-border-hover);
  box-shadow: var(--m-lift), 0 0 0 4px var(--m-ring);
}


/* ---- Buttons --------------------------------------------------------------------
   Colours stay with Tailwind classes; this only adds the feel. */
@layer components {
  .m-btn { display: inline-block; }
}
.m-btn {
  transition:
    transform var(--m-fast) var(--m-ease),
    box-shadow var(--m-fast) var(--m-ease),
    background-color var(--m-fast) ease,
    border-color var(--m-fast) ease,
    color var(--m-fast) ease,
    opacity var(--m-fast) ease;
}
.m-btn:not(:disabled):not([aria-disabled="true"]) { cursor: pointer; }
@media (hover: hover) {
  .m-btn:hover:not(:disabled):not([aria-disabled="true"]) {
    transform: translateY(-1px);
    box-shadow: var(--m-shadow-btn);
  }
}
.m-btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: scale(.97);
  box-shadow: none;
}

/* Submit in flight (class added by motion.js; the button stays ENABLED so its
   name/value is still posted). Spinner is an inline ring in currentColor. */
.is-busy {
  pointer-events: none;
  cursor: progress;
  opacity: .88;
}
button.is-busy::after,
a.is-busy::after {
  content: "";
  display: inline-block;
  box-sizing: border-box;
  width: .85em;
  height: .85em;
  margin-left: .55em;
  vertical-align: -.1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: m-spin .7s linear infinite;
}


/* ---- Rows -------------------------------------------------------------------------
   .m-row       list / table row hover tint
   .m-row-link  the whole row is clickable: gold 3px bar + sliding chevron.
                Give the last cell / row enough right padding (pr-8) for the chevron.
   Generic: every staff/client table body row gets the tint (rows that carry
   their own bg-* class keep it, so status-coloured rows are not repainted). */
.m-row,
.m-row-link,
main table tbody tr:not([class*="bg-"]) {
  transition: background-color var(--m-fast) ease;
}
@media (hover: hover) {
  .m-row:hover,
  .m-row-link:hover,
  main table tbody tr:not([class*="bg-"]):hover {
    background-color: var(--m-row);
  }
  main table tbody tr:not([class*="bg-"]):hover > .sticky {
    background-color: var(--m-row-solid);
  }
}
.m-row-link:focus-within { background-color: var(--m-row); }

/* Bar + chevron on a normal element ... */
.m-row-link:not(tr) { position: relative; }
.m-row-link:not(tr)::before,
tr.m-row-link > :first-child::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--m-gold);
  border-radius: 0 3px 3px 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--m-med) var(--m-ease);
  pointer-events: none;
}
.m-row-link:not(tr)::after,
tr.m-row-link > :last-child::after {
  content: "\203A";
  content: "\203A" / "";
  position: absolute;
  right: .75rem;
  top: 50%;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--m-text-muted);
  opacity: 0;
  transform: translate(-6px, -50%);
  transition: transform var(--m-med) var(--m-ease), opacity var(--m-fast) ease;
  pointer-events: none;
}
/* ... and on a table row, where the pseudo-elements live on the first / last cell
   (a pseudo-element on <tr> itself would create a phantom column). */
tr.m-row-link > :first-child,
tr.m-row-link > :last-child { position: relative; }

@media (hover: hover) {
  .m-row-link:not(tr):hover::before,
  tr.m-row-link:hover > :first-child::before { transform: scaleX(1); }
  .m-row-link:not(tr):hover::after,
  tr.m-row-link:hover > :last-child::after { opacity: 1; transform: translate(0, -50%); }
}
.m-row-link:not(tr):focus-within::before,
tr.m-row-link:focus-within > :first-child::before { transform: scaleX(1); }
.m-row-link:not(tr):focus-within::after,
tr.m-row-link:focus-within > :last-child::after { opacity: 1; transform: translate(0, -50%); }


/* ---- Sidebar -------------------------------------------------------------------
   The current page's link carries aria-current="page" (set in base.html). */
#sidebar-aside nav a { position: relative; }
#sidebar-aside nav a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20%;
  bottom: 20%;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--m-gold);
  opacity: 0;
  transform: scaleY(0);
  transition: transform var(--m-med) var(--m-ease), opacity var(--m-fast) ease;
  pointer-events: none;
}
#sidebar-aside nav a:focus-visible::before { opacity: .6; transform: scaleY(.55); }
#sidebar-aside nav a[aria-current="page"]::before { opacity: 1; transform: scaleY(1); }
html.js-motion:not(.m-settled) #sidebar-aside nav a[aria-current="page"]::before {
  animation: m-grow-y 420ms var(--m-ease) 150ms backwards;
}

/* Nudge the icon + label (not the count badge) and scale the icon. */
#sidebar-aside nav a > :not(.rounded-full) {
  transition: transform var(--m-med) var(--m-ease), scale var(--m-med) var(--m-ease);
}
#sidebar-aside nav a span > svg {
  transition: scale var(--m-med) var(--m-ease);
}
@media (hover: hover) {
  #sidebar-aside nav a:hover::before { opacity: .6; transform: scaleY(.55); }
  #sidebar-aside nav a[aria-current="page"]:hover::before { opacity: 1; transform: scaleY(1); }
  #sidebar-aside nav a:hover > :not(.rounded-full) { transform: translateX(2px); }
  #sidebar-aside nav a:hover svg { scale: 1.1; }
}
/* In the collapsed 4rem rail the icons are centred: no sideways nudge. */
@media (min-width: 768px) {
  .sidebar-collapsed #sidebar-aside nav a:hover > :not(.rounded-full) { transform: none; }
}
/* The sidebar is dark in both themes, so its focus ring must be light in both. */
#sidebar-aside :focus-visible { outline-color: #9fb3c8; }
/* ...except inside the Contact us popover, which is a white panel in light mode. */
html:not(.dark) #sidebar-aside [x-show] :focus-visible { outline-color: var(--color-brand-500); }

/* Brand mark: a light sheen sweeps across the logo link on hover, and a faint
   gold hairline closes the logo block. */
.m-sheen { position: relative; overflow: hidden; }
.m-sheen::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 55%;
  background: linear-gradient(100deg, transparent 0%, rgb(255 255 255 / .16) 50%, transparent 100%);
  transform: translateX(-130%);
  pointer-events: none;
}
@media (hover: hover) {
  .m-sheen:hover::after {
    transform: translateX(260%);
    transition: transform 520ms var(--m-ease);
  }
}
#sidebar-aside > a.m-sheen::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--m-gold) 50%, transparent);
  opacity: .6;
  pointer-events: none;
}


/* ---- Focus halo ---------------------------------------------------------------------
   EXTENDS the existing :focus-visible outline in input.css (kept as is). Links,
   buttons and disclosure summaries also get a short soft halo; it is an
   animation, so it never replaces a control's resting shadow. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible {
  animation: m-halo 340ms var(--m-ease);
}
/* Elements that carry their own resting/focus shadow keep it (a running animation would override it). */
.m-card-link:focus-visible,
.m-btn:focus-visible { animation: none; }


/* ---- Django message banners --------------------------------------------------------- */
html.js-motion:not(.m-settled) .m-flash {
  animation: m-drop 300ms var(--m-ease) backwards;
}


/* ---- Empty states --------------------------------------------------------------------
   <div class="m-empty"> <svg aria-hidden="true">...</svg> <p>Sentence.</p> </div> */
@layer components {
  .m-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--m-text-muted);
  }
  .m-empty > svg {
    width: 2rem;
    height: 2rem;
    color: var(--m-icon-muted);
  }
}
html.js-motion:not(.m-settled) .m-empty {
  animation: m-rise 360ms var(--m-ease) 80ms backwards;
}


/* ---- Dropzone -------------------------------------------------------------------------
   motion.js toggles .is-dragover on [data-dropzone] during a file drag. */
@layer components {
  .m-dropzone {
    border: 2px dashed var(--m-dz-border);
    border-radius: .75rem;
    background-color: var(--m-dz-bg);
  }
}
.m-dropzone {
  transition:
    border-color var(--m-med) ease,
    background-color var(--m-med) ease,
    box-shadow var(--m-med) var(--m-ease);
}
@media (hover: hover) {
  .m-dropzone:hover {
    border-color: var(--m-dz-border-hover);
    background-color: var(--m-dz-bg-hover);
  }
}
.m-dropzone:focus-within {
  border-color: var(--m-border-hover);
  box-shadow: 0 0 0 4px var(--m-ring);
}
.m-dropzone.is-dragover > * { pointer-events: none; }
.m-dropzone.is-dragover {
  border-color: var(--m-gold);
  background-color: var(--m-dz-bg-active);
  box-shadow: 0 0 0 4px var(--m-gold-ring);
}


/* ---- Skeleton (loading placeholder) ------------------------------------------------------
   Sweep is a transformed pseudo-element, so it is compositor-only. */
.m-skeleton {
  position: relative;
  overflow: hidden;
  background-color: var(--m-skel);
  border-radius: .375rem;
  color: transparent;
}
.m-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent 0%, var(--m-shimmer) 50%, transparent 100%);
  transform: translateX(-100%);
  animation: m-shimmer 1.5s ease-in-out infinite;
}


/* ---- Page leave / theme switch -------------------------------------------------------------
   .m-leaving is set on <main> by motion.js when a same-site link is clicked:
   an instant dim, then the browser navigates normally (no fade-then-wait). */
#main { transition: opacity 160ms ease; }
#main.m-leaving { opacity: .6; transition-duration: 120ms; }

/* Theme switch: briefly cross-fade colours (class set by motion.js, skipped on big pages). */
html.m-theme-fade,
html.m-theme-fade *,
html.m-theme-fade *::before,
html.m-theme-fade *::after {
  transition:
    background-color 260ms ease,
    color 260ms ease,
    border-color 260ms ease,
    fill 260ms ease,
    stroke 260ms ease,
    box-shadow 260ms ease,
    outline-color 260ms ease !important;
}


/* ---- Login: split brand panel -----------------------------------------------------------------
   A refined entrance, a thin gold rule under the logo and a faint gold hairline on the panel edge.
   No marketing copy. */
.m-brand-panel { position: relative; }
.m-brand-panel::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 1px;
  background: linear-gradient(to bottom, transparent, var(--m-gold) 50%, transparent);
  opacity: .5;
  pointer-events: none;
}
.m-gold-rule {
  width: 4rem;
  height: 1px;
  margin-top: 1.5rem;
  background: var(--m-gold);
  transform-origin: center;
}
/* In dark mode the panel turns white: use the deeper gold so the rule still reads. */
:root.dark .m-gold-rule,
:root.dark .m-brand-panel::after { background: var(--m-gold-deep); }
:root.dark .m-brand-panel::after {
  background: linear-gradient(to bottom, transparent, var(--m-gold-deep) 50%, transparent);
}
html.js-motion:not(.m-settled) .m-brand-panel > img {
  animation: m-fade 520ms var(--m-ease) backwards;
}
html.js-motion:not(.m-settled) .m-gold-rule {
  animation: m-draw 640ms var(--m-ease) 260ms backwards;
}
html.js-motion:not(.m-settled) .m-brand-panel > p {
  animation: m-rise 420ms var(--m-ease) 440ms backwards;
}


/* ---- Smart batch upload review ----------------------------------------------------------------------
   Status chips pop in after their row rises; a row flashes a soft green when the client settles it (turns an
   unknown or "please check" row into a confirmed choice); the summary counters count up (data-countup). */
@keyframes m-pop {
  from { opacity: 0; transform: scale(.9); }
  to { opacity: 1; transform: none; }
}
@keyframes m-confirmed {
  from { background-color: var(--m-ok-tint); }
  to { background-color: transparent; }
}
html.js-motion .m-pop {
  animation: m-pop 220ms var(--m-ease) backwards;
  animation-delay: calc(var(--i, 0) * var(--m-step) + 140ms);
}
.is-confirmed { animation: m-confirmed 900ms var(--m-ease); }
/* The row of a file we could not read keeps a calm amber edge until the client has chosen. */
[data-review-row][data-status="unknown"], [data-review-row][data-status="check"] { box-shadow: inset 3px 0 0 var(--m-gold); }
[data-review-row].is-settled { box-shadow: none; transition: box-shadow var(--m-med) var(--m-ease); }

/* ---- Messages -------------------------------------------------------------------------------------------
   A message you just sent eases in (the others are already there, so nothing replays on the 30 s refresh);
   arriving at a conversation by a link (#messages) scrolls it into view and rings it in gold for a moment. */
@keyframes m-msg-in {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-spot {
  0%   { opacity: 0; }
  25%  { opacity: 1; }
  100% { opacity: 0; }
}
html.js-motion .m-msg-in { animation: m-msg-in 260ms var(--m-ease) backwards; }
.m-spotlight-host { position: relative; }
.m-spotlight-host.is-spotlit::after {
  content: "";
  position: absolute;
  inset: -8px;
  border: 2px solid var(--m-gold);
  border-radius: .9rem;
  pointer-events: none;
  animation: m-spot 1500ms var(--m-ease) 1 forwards;
}

/* ---- Reduced motion: the kill-switch (keep this LAST) --------------------------------------------
   Turns off every animation and transition. Static end states (the gold bar,
   the title hairline, a busy button's ring) are all still drawn. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  .m-skeleton::after { animation: none !important; }
}


/* ---- Type-to-search picker (static/js/fuzzy-select.js upgrades <select data-fuzzy>) ------------------------ */
.fz { position: relative; width: 100%; }
.fz-native {
  position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; overflow: hidden;
}
.fz-input {
  display: block; width: 100%; min-height: 2.75rem; border-radius: .5rem; padding: .5rem 2.25rem .5rem .75rem;
  font: inherit; font-size: .8rem; color: #0f172a; background-color: #fff;
  border: 1px solid #cbd5e1;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2364748b' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .6rem center; background-size: 1rem;
  transition: border-color var(--m-fast) ease, box-shadow var(--m-fast) ease;
}
.fz-input:focus { outline: none; border-color: #486581; box-shadow: 0 0 0 4px var(--m-ring); }
.fz-input::placeholder { color: var(--m-text-muted); }
.fz.fz-disabled .fz-input { opacity: .55; cursor: not-allowed; }
.fz-list {
  position: absolute; z-index: 40; left: 0; right: 0; margin-top: .25rem; max-height: 17rem; overflow-y: auto;
  padding: .25rem; list-style: none; border: 1px solid var(--m-border); border-radius: .625rem;
  background: var(--m-surface); box-shadow: var(--m-lift);
}
.fz-list[hidden] { display: none; }
.fz-option {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .125rem .5rem; padding: .5rem .625rem;
  border-radius: .5rem; cursor: pointer; font-size: .8rem; color: #0f172a;
}
.fz-option.fz-active { background: var(--m-row-solid); }
.fz-option[aria-selected="true"] .fz-label { font-weight: 600; }
.fz-label { font-weight: 500; }
.fz-badge {
  font-size: .65rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: #92400e;
  background: #fef3c7; border-radius: 999px; padding: 0 .4rem;
}
.fz-place { flex-basis: 100%; font-size: .72rem; color: var(--m-text-muted); }
.fz-note { padding: .5rem .625rem; font-size: .75rem; color: var(--m-text-muted); }
:root.dark .fz-input { color: #e2e8f0; background-color: #0f172a; border-color: #475569; }
:root.dark .fz-input:focus { border-color: #9fb3c8; }
:root.dark .fz-option { color: #e2e8f0; }
:root.dark .fz-badge { color: #fde68a; background: rgb(251 191 36 / .16); }
@media (prefers-reduced-motion: reduce) { .fz-input { transition: none; } }

/* Sidebar notification dot + count: a small pop when it appears (gated like the rest of the motion layer). */
@keyframes notif-pop { 0% { transform: scale(.4); opacity: 0; } 70% { transform: scale(1.15); } 100% { transform: scale(1); opacity: 1; } }
html.js-motion .notif-badge { animation: notif-pop .24s ease-out both; }
@media (prefers-reduced-motion: reduce) { html.js-motion .notif-badge { animation: none; } }

/* ---- Sticky action bar ------------------------------------------------------------ */
/* The review page's "Send N documents" button: stays at the bottom of the screen while a long list scrolls, so the
   client never has to hunt for it. A card on the page surface, so it reads in light and dark. */
@layer components {
  .m-stickybar {
    position: sticky;
    bottom: .75rem;
    z-index: 20;
    padding: .75rem;
    background-color: var(--m-surface);
    border: 1px solid var(--m-border);
    border-radius: .75rem;
    box-shadow: var(--m-lift);
  }
}


/* ---- Forms outstanding bars (staff Operations) ------------------------------------------------------------------
   The proportional bar grows in from the left once. Only gated by html.js-motion, so with JS off the bar is simply
   drawn. transform-only (GPU friendly); the reduced-motion kill-switch below it turns the animation off. */
html.js-motion:not(.m-settled) .m-bar rect {
  transform-origin: left center;
  transform-box: fill-box;
  animation: m-bar-grow 520ms var(--m-ease) both;
}
@keyframes m-bar-grow {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
@media (prefers-reduced-motion: reduce) {
  .m-bar rect { animation: none !important; }
}
