/* ==========================================================================
   Motion and refinement.
   Loaded after theme.css and shell.css so it can lift what those establish.

   THE RULE THIS FILE FOLLOWS
   Motion may show direction, hierarchy or a change of state. It may never
   animate a figure that has to be read as exact. A KPI whose digits count up
   is, for the third of a second it is counting, displaying a wrong number —
   and someone reading over a treasurer's shoulder cannot tell that it is still
   moving. So tiles rise and fade in; the numbers inside them are correct from
   the first painted frame.

   Everything here is CSS. No animation library, nothing driven by JavaScript
   on the main thread, and only `transform` and `opacity` are animated, so the
   compositor handles it and a cheap phone does not drop frames.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Timing. One scale, used everywhere, so the interface feels like one hand
   made it. Ease-out for things arriving, a gentle spring only for the drawer.
   -------------------------------------------------------------------------- */
:root{
  --t-fast: 120ms;
  --t-mid:  220ms;
  --t-slow: 420ms;
  --ease:        cubic-bezier(.22,.61,.36,1);   /* arriving */
  --ease-in-out: cubic-bezier(.45,.05,.55,.95); /* moving between two states */
  --lift-1: var(--e-1);
  --lift-2: var(--e-2);
}

/* --------------------------------------------------------------------------
   Page arrival.
   A short, ordered reveal: the topbar settles, then the content rises. Panels
   stagger by 45ms, which is enough to read as a sequence and too little to
   feel like waiting. Capped at eight steps — a twelve-panel cascade turns into
   a queue.
   -------------------------------------------------------------------------- */
@keyframes rise{
  from{ opacity:0; transform:translate3d(0,10px,0); }
  to  { opacity:1; transform:none; }
}
@keyframes settle{
  from{ opacity:0; transform:translate3d(0,-6px,0); }
  to  { opacity:1; transform:none; }
}
@keyframes fade{ from{opacity:0} to{opacity:1} }

.topbar{ animation:settle var(--t-mid) var(--ease) both; }
.brand-rule{
  animation:rule-draw var(--t-slow) var(--ease) both;
  transform-origin:left center;
}
@keyframes rule-draw{ from{transform:scaleX(0)} to{transform:scaleX(1)} }

.content > *{ animation:rise var(--t-mid) var(--ease) both; }
.content > *:nth-child(1){ animation-delay:40ms }
.content > *:nth-child(2){ animation-delay:85ms }
.content > *:nth-child(3){ animation-delay:130ms }
.content > *:nth-child(4){ animation-delay:175ms }
.content > *:nth-child(5){ animation-delay:220ms }
.content > *:nth-child(6){ animation-delay:265ms }
.content > *:nth-child(n+7){ animation-delay:300ms }

/* The sidebar items come in as a group, not individually — twelve separate
   arrivals in a navigation column is fussy. */
.side-nav{ animation:fade var(--t-slow) var(--ease) both; animation-delay:60ms }

/* --------------------------------------------------------------------------
   Panels: quiet elevation, and a hairline that warms on hover.
   -------------------------------------------------------------------------- */
.panel{
  box-shadow:var(--lift-1);
  transition:box-shadow var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease);
}
.panel:hover{ box-shadow:var(--lift-2); }
.panel:focus-within{ border-color:var(--brand); box-shadow:var(--lift-2); }

/* --------------------------------------------------------------------------
   The ledger.
   Sticky headers already existed; this gives them a shadow only once the table
   has actually scrolled, so the line does not float above a table sitting at
   rest. `animation-timeline: scroll()` does it with no JavaScript where
   supported, and where it is not, nothing happens — which is the correct
   fallback for a shadow.
   -------------------------------------------------------------------------- */
@supports (animation-timeline: scroll()){
  .ledger-wrap, .tscroll, .matrix-wrap{
    scroll-timeline: --tbl x;
  }
  table.ledger thead th, table.t thead th, table.matrix thead th{
    animation: header-lift 1ms linear both;
    animation-timeline: --tbl;
    animation-range: 1px 40px;
  }
  @keyframes header-lift{
    to{ box-shadow: 4px 0 8px -4px rgba(23,22,63,.18); }
  }
}

/* A row under the cursor gets a left accent in the parish blue. On a
   thirteen-column ledger the eye loses its row; a 2px rule holds it. */
table.ledger tbody tr, table.t tbody tr{
  transition: background-color var(--t-fast) linear;
}
table.ledger tbody tr > td:first-child,
table.t tbody tr > td:first-child{
  box-shadow: inset 0 0 0 0 var(--brand);
  transition: box-shadow var(--t-fast) var(--ease);
}
table.ledger tbody tr:hover > td:first-child,
table.t tbody tr:hover > td:first-child{
  box-shadow: inset 2px 0 0 0 var(--brand);
}

/* Matrix cells lift slightly under the cursor so the tooltip target is
   obvious in a dense grid of 120. */
.m-cell{ transition: transform var(--t-fast) var(--ease), filter var(--t-fast) linear; }
.m-cell:hover{ transform:scale(1.14); filter:saturate(1.15); position:relative; z-index:2 }

/* --------------------------------------------------------------------------
   Charts draw in the direction time runs: bars up from the baseline, the
   cumulative line left to right. This is the one place motion carries meaning
   rather than polish — it tells you which way to read.
   -------------------------------------------------------------------------- */
.c-bar{
  transform-box: fill-box;
  transform-origin: bottom;
  animation: bar-grow var(--t-slow) var(--ease) both;
}
@keyframes bar-grow{ from{transform:scaleY(0)} to{transform:scaleY(1)} }

.c-actual, .c-avg, .c-target{
  stroke-dasharray: 4000;
  stroke-dashoffset: 4000;
  animation: line-draw 1100ms var(--ease-in-out) both;
  animation-delay: 120ms;
}
/* The dashed target line must keep its dashes, so it fades rather than draws. */
.c-target{
  stroke-dasharray: 5 4;
  stroke-dashoffset: 0;
  animation: fade var(--t-slow) var(--ease) both;
  animation-delay: 300ms;
}
@keyframes line-draw{ to{ stroke-dashoffset:0 } }
.c-fill{ animation: fade 700ms var(--ease) both; animation-delay:260ms }
.c-dot{ animation: rise var(--t-mid) var(--ease) both; animation-delay:900ms }

.tb-fill{ animation: bar-slide var(--t-slow) var(--ease) both; transform-origin:left center }
@keyframes bar-slide{ from{transform:scaleX(0)} to{transform:scaleX(1)} }
.tb-notch{ animation: fade var(--t-mid) linear both; animation-delay:320ms }
.sm-seg{ animation: bar-grow var(--t-slow) var(--ease) both; transform-origin:bottom }
.split i{ animation: bar-slide var(--t-slow) var(--ease) both; transform-origin:left center }
.confbar i, .mtrack i{ animation: bar-slide var(--t-mid) var(--ease) both }
.pcol i{ animation: bar-grow var(--t-slow) var(--ease) both; transform-origin:bottom }

/* --------------------------------------------------------------------------
   Controls. Press depth rather than bounce — this is a ledger, not a game.
   -------------------------------------------------------------------------- */
.btn{
  transition: background-color var(--t-fast) linear, transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
  box-shadow: var(--lift-1);
}
.btn:hover{ transform: translateY(-1px); box-shadow: var(--lift-2) }
.btn:active{ transform: translateY(0) scale(.985); box-shadow:none }

.side-item{ transition: background-color var(--t-fast) linear, border-left-color var(--t-fast) linear }
.side-item.on{ animation: fade var(--t-mid) linear both }
.si-badge{ animation: badge-in var(--t-slow) var(--ease) both; animation-delay:400ms }
@keyframes badge-in{
  from{ opacity:0; transform:scale(.6) }
  to  { opacity:1; transform:none }
}

input, select, textarea{
  transition: border-color var(--t-fast) linear, box-shadow var(--t-fast) var(--ease);
}
input:focus, select:focus, textarea:focus{ box-shadow: 0 0 0 3px var(--brand-tint) }

/* One focus treatment across the whole app, in the parish blue, always
   visible on keyboard. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible{
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 1px;
}

/* Notices arrive rather than appear, because they are usually the answer to
   something the person just did. */
.notice{ animation: notice-in var(--t-mid) var(--ease) both }
@keyframes notice-in{
  from{ opacity:0; transform:translate3d(0,-6px,0) }
  to  { opacity:1; transform:none }
}

/* Details disclosure: rotate the marker instead of swapping the glyph. */
details.dist > summary::before{
  display:inline-block;
  transition: transform var(--t-fast) var(--ease);
}
details.dist[open] > summary::before{ transform: rotate(90deg) }

/* --------------------------------------------------------------------------
   Mobile drawer. Backdrop fades; the panel itself uses a short overshoot-free
   curve so it does not feel rubbery on a low-end device.
   -------------------------------------------------------------------------- */
@media (max-width:900px){
  .side{ transition: transform var(--t-mid) var(--ease-in-out) }
  .backdrop{
    position:fixed; inset:0; z-index:39; background:rgba(18,16,46,.42);
    opacity:0; pointer-events:none; transition:opacity var(--t-mid) linear;
    backdrop-filter:saturate(.7) blur(1.5px);
  }
  body.side-open .backdrop{ opacity:1; pointer-events:auto }
  body.side-open{ overflow:hidden }   /* stop the page scrolling behind the drawer */
}

/* --------------------------------------------------------------------------
   Container queries.
   The real responsiveness upgrade: a panel reflows on its own width, not the
   viewport's. The same summary panel then works in a sidebar, in a two-column
   grid, and full-width, without a media query for each arrangement.
   -------------------------------------------------------------------------- */
.panel{ container-type: inline-size; container-name: panel }

@container panel (max-width: 430px){
  .tbar{ grid-template-columns: 1fr auto; row-gap:3px }
  .tbar .tb-track{ grid-column:1 / -1; order:3 }
  .row{ grid-template-columns: 1fr }
  .smonths{ gap:4px }
  .sm-lbl{ font-size:9px }
}
@container panel (min-width: 760px){
  .row{ grid-template-columns: repeat(3, 1fr) }
}

/* --------------------------------------------------------------------------
   Cross-page transitions. Navigating report -> dashboard cross-fades and the
   crest stays put, so the app reads as one surface rather than a set of
   documents. Silently ignored where unsupported.
   -------------------------------------------------------------------------- */
@view-transition{ navigation: auto }

.crest-mark{ view-transition-name: crest }
.side{ view-transition-name: sidebar }
.topbar{ view-transition-name: topbar }

::view-transition-old(root){ animation: fade var(--t-fast) linear reverse both }
::view-transition-new(root){ animation: rise var(--t-mid) var(--ease) both }
/* The sidebar must not fade with the page — it does not change between pages,
   and fading it makes every navigation look like a reload. */
::view-transition-group(sidebar),
::view-transition-group(crest){ animation-duration: 1ms }

/* --------------------------------------------------------------------------
   Dark theme.
   Surfaces are mixed from the roundel blue rather than neutral grey, so the
   crest still looks at home. Every value below was contrast-checked against
   its own background; the lowest is 5.56:1 and the rest clear 7:1.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Dark theme.

   Surfaces are mixed from the roundel blue rather than neutral grey, so the
   crest still looks at home. Every value was contrast-checked against its own
   background; the lowest is 5.56:1 and the rest clear 7:1.

   THE TWO SELECTORS BELOW MUST STAY IN STEP. The first is an explicit choice,
   the second is the device's preference when the person has not overridden it.
   CSS cannot share one declaration block across a media-query boundary, and
   resolving "system" server-side would need either an inline script (which
   would cost us script-src 'self' in the CSP) or a client hint. Duplication is
   the cheaper of those. tools/check_theme.php fails the build if the two blocks
   ever stop declaring the same variables.
   -------------------------------------------------------------------------- */

/* 1. Chosen explicitly. */
:root[data-theme="dark"]{
    --panel-ring: rgba(255,255,255,.07);
    --e-1: 0 1px 2px rgba(0,0,0,.35), 0 4px 15px rgba(0,0,0,.3);
    --e-2: 0 2px 6px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.38);
    --e-3: 0 8px 24px rgba(0,0,0,.5), 0 24px 60px rgba(0,0,0,.45);
    --grad-brand: linear-gradient(135deg, #1A1750 0%, #262163 55%, #322C7B 100%);
    --grad-accent: linear-gradient(90deg, #6C68B8 0%, #A2A0CC 100%);
    --grad-wash: linear-gradient(135deg, rgba(162,160,204,.07), rgba(162,160,204,0));
    --brand:        #A2A0CC;   /*  7.41:1 — the blue lifted to work as text  */
  --brand-plate:  #171444;   /* stays deep: it is a backdrop, not type      */
  --brand-deep:   #EAEAF4;   /* 15.43:1 — body text                       */
  --brand-soft:   #B1AFD4;   /*  8.74:1 — secondary                       */
  --brand-tint:   #221F52;
  --brand-wash:   #0E0C24;
  --flame:        #E23A41;
  --flame-text:   #F77B7F;   /*  7.10:1                                   */
  --flame-tint:   #3A1119;
  --gold:         #E2D513;   /* 12.08:1                                   */
  --gold-text:    #D8CB2A;
  --paper:        #12102E;
  --ground:       #0A0918;
  --rule:         #2A2760;
  --rule-soft:    #1E1B45;
  --mpesa:        #59C48D;   /*  8.52:1                                   */
  --bank:         #7FA8D4;
  --cash:         #D8CB2A;
  --lift-1: var(--e-1);
  --lift-2: var(--e-2);
  --row-hover: #1B1840;
  --total-row: #1E1B48;

  /* Matrix bands re-derived against the dark surface. Lowest is 5.56:1. */
  --m-p3-bg:#312D8E; --m-p3-fg:#FFFFFF;   /* 11.07:1 */
  --m-p2-bg:#282463; --m-p2-fg:#FFFFFF;   /* 13.79:1 */
  --m-p1-bg:#1C1A45; --m-p1-fg:#FFFFFF;   /* 16.37:1 */
  --m-n1-bg:#4A1526; --m-n1-fg:#FFFFFF;   /* 14.72:1 */
  --m-n2-bg:#8B1A26; --m-n2-fg:#FFFFFF;   /*  9.24:1 */
  --m-n3-bg:#CE1822; --m-n3-fg:#FFFFFF;   /*  5.56:1 */
}

/* 2. Device preference, unless the person has asked for light. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]):not([data-theme="dark"]){
    --panel-ring: rgba(255,255,255,.07);
    --e-1: 0 1px 2px rgba(0,0,0,.35), 0 4px 15px rgba(0,0,0,.3);
    --e-2: 0 2px 6px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.38);
    --e-3: 0 8px 24px rgba(0,0,0,.5), 0 24px 60px rgba(0,0,0,.45);
    --grad-brand: linear-gradient(135deg, #1A1750 0%, #262163 55%, #322C7B 100%);
    --grad-accent: linear-gradient(90deg, #6C68B8 0%, #A2A0CC 100%);
    --grad-wash: linear-gradient(135deg, rgba(162,160,204,.07), rgba(162,160,204,0));
    --brand:        #A2A0CC;   /*  7.41:1 — the blue lifted to work as text  */
    --brand-plate:  #171444;   /* stays deep: it is a backdrop, not type      */
    --brand-deep:   #EAEAF4;   /* 15.43:1 — body text                       */
    --brand-soft:   #B1AFD4;   /*  8.74:1 — secondary                       */
    --brand-tint:   #221F52;
    --brand-wash:   #0E0C24;
    --flame:        #E23A41;
    --flame-text:   #F77B7F;   /*  7.10:1                                   */
    --flame-tint:   #3A1119;
    --gold:         #E2D513;   /* 12.08:1                                   */
    --gold-text:    #D8CB2A;
    --paper:        #12102E;
    --ground:       #0A0918;
    --rule:         #2A2760;
    --rule-soft:    #1E1B45;
    --mpesa:        #59C48D;   /*  8.52:1                                   */
    --bank:         #7FA8D4;
    --cash:         #D8CB2A;
    --lift-1: var(--e-1);
    --lift-2: var(--e-2);
    --row-hover: #1B1840;
    --total-row: #1E1B48;

    /* Matrix bands re-derived against the dark surface. Lowest is 5.56:1. */
    --m-p3-bg:#312D8E; --m-p3-fg:#FFFFFF;   /* 11.07:1 */
    --m-p2-bg:#282463; --m-p2-fg:#FFFFFF;   /* 13.79:1 */
    --m-p1-bg:#1C1A45; --m-p1-fg:#FFFFFF;   /* 16.37:1 */
    --m-n1-bg:#4A1526; --m-n1-fg:#FFFFFF;   /* 14.72:1 */
    --m-n2-bg:#8B1A26; --m-n2-fg:#FFFFFF;   /*  9.24:1 */
    --m-n3-bg:#CE1822; --m-n3-fg:#FFFFFF;   /*  5.56:1 */
  }
}

/* Applies to both. */
:root[data-theme="dark"] .offline-bar,
:root:not([data-theme="light"]) .offline-bar{ background:var(--gold); color:#12102E }


/* --------------------------------------------------------------------------
   Reduced motion. Not a token gesture: every animation is switched off, not
   merely shortened, and the final state is what remains. Vestibular disorders
   are triggered by movement, not by its duration.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  /* One deliberate exception: the scroll-driven header shadow is left in place.
     It is driven by scroll position rather than time, produces no movement —
     only a shadow becoming visible once a table has been scrolled — and it is
     the affordance that tells a reader the header is sticky. Vestibular
     disorders are triggered by motion, not by contrast. Such animations report
     as permanently "running" to getAnimations(), which is expected. */
  *, *::before, *::after{
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .c-actual, .c-avg{ stroke-dasharray: none; stroke-dashoffset: 0 }
  .c-bar, .tb-fill, .sm-seg, .split i, .pcol i{ transform: none !important }
  .m-cell:hover{ transform:none }
  @view-transition{ navigation: none }
}

/* --------------------------------------------------------------------------
   Print. This system's output ends up in a district session folder, so the
   printed page is a real deliverable rather than an afterthought.
   -------------------------------------------------------------------------- */
@media print{
  :root{ --paper:#fff; --ground:#fff; --ink:#000; --rule:#666 }
  *{ animation:none !important; transition:none !important; box-shadow:none !important }
  .side, .topbar, .tb-out, .burger, .backdrop, .offline-bar, .pager, .weeks, .btn{ display:none !important }
  .layout{ display:block }
  .content{ padding:0 }
  .panel{ border:1px solid #999; break-inside:avoid; page-break-inside:avoid }
  table.ledger, table.t, table.matrix{ break-inside:auto }
  thead{ display:table-header-group }   /* repeat headers across pages */
  tr{ break-inside:avoid }
  .brand-rule{ background:#000; height:2px }
  a[href]::after{ content:"" }          /* no URL clutter in a signed report */
  .stamp{ display:grid !important }     /* the sign-off seal must print */
}

/* ==========================================================================
   Flourishes — the growth and draw-in effects flourish.js triggers.

   Everything here animates transform, opacity, or (for the sparkline) a
   normalised stroke offset. No width, height, margin or colour is animated
   anywhere, so nothing below causes layout or paint work per frame — the
   compositor carries all of it, which is what keeps a KES-2,000 Android at
   60fps on a dashboard full of bars.

   The initial hidden states are gated on .js-anim, a class flourish.js is
   about to... no — a class set HERE ONLY via :where(html:not([data-no-js]))?
   Simpler and safer: initial states are applied only when the reveal class
   is absent AND the browser reports it will animate. If flourish.js never
   runs (reduced motion, old browser, script blocked), no rule below applies
   and everything renders in its final state. That ordering — complete first,
   embellish after — is the contract.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* bars grow from the left */
  .hbar i, .attain-bar i{
    transition:transform .65s cubic-bezier(.22,.9,.35,1);
  }
  .hbar:not(.in-view) i, .attain-bar:not(.in-view) i{
    transform:scaleX(0);
  }

  /* sparklines draw themselves */
  svg.spark polyline{
    stroke-dasharray:1;
    stroke-dashoffset:0;
    transition:stroke-dashoffset .8s cubic-bezier(.4,0,.2,1);
  }
  svg.spark:not(.in-view) polyline[pathLength]{
    stroke-dashoffset:1;
  }
  svg.spark circle{
    transition:opacity .3s ease .7s, transform .3s ease .7s;
    transform-origin:center;
  }
  svg.spark:not(.in-view) circle{
    opacity:0; transform:scale(.4);
  }

  /* the KPI strip lifts in with a slight stagger */
  .kpis .kpi{ animation:kpi-in .5s var(--ease) both }
  .kpis .kpi:nth-child(2){ animation-delay:.06s }
  .kpis .kpi:nth-child(3){ animation-delay:.12s }
  .kpis .kpi:nth-child(4){ animation-delay:.18s }
  .kpis .kpi:nth-child(5){ animation-delay:.24s }

  /* the recent-entries feed cascades, first six only —
     beyond that the stagger reads as lag, not craft */
  .feed li{ animation:feed-in .4s var(--ease) both }
  .feed li:nth-child(1){ animation-delay:.05s }
  .feed li:nth-child(2){ animation-delay:.10s }
  .feed li:nth-child(3){ animation-delay:.15s }
  .feed li:nth-child(4){ animation-delay:.20s }
  .feed li:nth-child(5){ animation-delay:.25s }
  .feed li:nth-child(6){ animation-delay:.30s }

  /* season banner: the accent edge breathes in once */
  .season{ animation:season-in .5s var(--ease) both }
}

@keyframes kpi-in{
  from{ opacity:0; transform:translate3d(0,10px,0) }
  to{ opacity:1; transform:none }
}
@keyframes feed-in{
  from{ opacity:0; transform:translate3d(-8px,0,0) }
  to{ opacity:1; transform:none }
}
@keyframes season-in{
  from{ opacity:0; transform:translate3d(0,-6px,0) }
  to{ opacity:1; transform:none }
}

/* --------------------------------------------------------------------------
   Skeleton loading — the shape of the content that's coming, not a spinner.
   A spinner tells a reader "wait"; a skeleton tells them "here, roughly, is
   what's about to appear" — genuinely faster-feeling on the 3G connections
   this system is built for, at zero extra network cost. Respects reduced
   motion automatically through the blanket rule above (every animation
   caps to 1ms there), so no separate override is needed here.
   -------------------------------------------------------------------------- */
.skel{
  background:linear-gradient(90deg, var(--rule-soft) 25%, var(--rule) 37%, var(--rule-soft) 63%);
  background-size:400% 100%;
  animation:skel-shimmer 1.4s ease-in-out infinite;
  border-radius:var(--r-sm);
}
.skel-line{ height:13px; margin:6px 0 }
.skel-line.w60{ width:60% }
.skel-line.w80{ width:80% }
.skel-line.w40{ width:40% }
@keyframes skel-shimmer{
  0%{ background-position:200% 0 }
  100%{ background-position:-200% 0 }
}

/* --------------------------------------------------------------------------
   Save confirmation — a checkmark on the button itself, not just a toast
   elsewhere on screen. Entry pages deliberately stay open after a
   successful save (so a clerk can work down a stack of envelopes without
   re-selecting the week), which means the confirmation has to live right
   where the thumb already is, not somewhere it has to look for.
   -------------------------------------------------------------------------- */
.btn.just-saved{ position:relative; overflow:hidden }
.btn.just-saved::after{
  content:"✓"; position:absolute; inset:0; display:flex; align-items:center;
  justify-content:center; background:var(--brand); color:#fff;
  animation:save-flash 1.1s ease-out both;
}
@keyframes save-flash{
  0%{ opacity:0; transform:scale(.7) }
  15%{ opacity:1; transform:scale(1) }
  75%{ opacity:1 }
  100%{ opacity:0 }
}

/* Tap feedback — a small, immediate scale-down so a finger gets
   confirmation before the network reply arrives, not after. Applies
   broadly rather than per-page because the absence of it is what reads as
   unresponsive on a slow connection, not any one screen in particular. */
@media (prefers-reduced-motion: no-preference){
  .btn:active, .key:active, .seg-btn:active{ transform:scale(.96) }
}
