/* Motion and depth over every theme (public/fx.js).
 *
 * Artur, 14 Oct 2026: modern, professional, with depth and motion, no native
 * popups or pickers, and NOT the look of an AI-generated page. So none of its
 * tells: no drifting colour blobs, no gradient text or bars, no glowing
 * coloured shadows, no frosted glass, no light sweeping across buttons, no
 * cards that tilt. What is here is what well-made apps do: the theme's own
 * solid colours, a hairline edge, shadows that look like shadows, and
 * movement only where something actually happens: a sheet opening, a row
 * arriving, a switch flipping, day turning to night.
 *
 * Kept from styles.css on purpose: nothing a thumb presses shrinks or moves.
 * Hover effects need a real mouse (html.fx-mouse), so a phone never gets them.
 *
 * Only transform and opacity move, so a phone composites it on the GPU.
 * html.fx-calm (Appearance, Effects: Calm) and the phone's own "reduce
 * motion" stop every movement and keep everything else.
 */

:root{
  --spring:cubic-bezier(.32,1.25,.6,1);   /* a sheet settling, barely past its mark */
  --glide:cubic-bezier(.2,.8,.2,1);
  --fx-motion:1;                           /* read by the tests: 1 moving, 0 still */
  --sh-lift:0 1px 2px rgba(16,24,20,.06), 0 8px 20px -6px rgba(16,24,20,.14);
  --sh-pop:0 2px 6px rgba(16,24,20,.08), 0 18px 44px -12px rgba(16,24,20,.24);
}
html[data-theme="dark"]{
  --sh-lift:0 1px 2px rgba(0,0,0,.4), 0 10px 24px -8px rgba(0,0,0,.6);
  --sh-pop:0 2px 8px rgba(0,0,0,.45), 0 22px 50px -14px rgba(0,0,0,.7);
}
html.fx-calm{ --fx-motion:0; }
@media (prefers-reduced-motion: reduce){ :root{ --fx-motion:0; } }

/* ---- how far down the page: a measuring tape ------------------------------
   The one odd thing here, and it is his trade: down the right-hand edge runs a
   tape, marked every 10cm with a longer mark each metre. It slides as the page
   moves, and while it moves a tab reads off how far he has come, one pixel to
   the centimetre. */
.fx-tape{ position:fixed; top:0; bottom:0; right:0; width:14px; z-index:15; pointer-events:none;
  background-color:var(--secondary);
  background-image:
    linear-gradient(to bottom, rgba(0,0,0,.55) 0 1.5px, transparent 1.5px),
    linear-gradient(to bottom, rgba(0,0,0,.35) 0 1px, transparent 1px);
  background-size:100% 100px, 45% 10px;
  background-repeat:repeat-y; background-position:right 0 top var(--fx-tape,0px), right 0 top var(--fx-tape,0px);
  box-shadow:inset 1px 0 0 rgba(0,0,0,.18), -1px 0 4px rgba(0,0,0,.08); opacity:.92; }
.fx-tape-tab{ position:fixed; right:14px; top:50%; z-index:16; pointer-events:none;
  font:800 11px/1 var(--sans); letter-spacing:.04em; font-variant-numeric:tabular-nums;
  color:var(--on-secondary); background:var(--secondary); padding:6px 8px 6px 9px; border-radius:6px 0 0 6px;
  box-shadow:-1px 1px 4px rgba(0,0,0,.18); transform:translateY(-50%) translateX(6px); opacity:0;
  transition:opacity .25s var(--glide), transform .25s var(--glide); }
.fx-tape-tab::after{ content:""; position:absolute; right:-14px; top:50%; width:14px; height:2px; margin-top:-1px; background:var(--on-secondary); }
.fx-tape-tab.on{ opacity:1; transform:translateY(-50%); }
@media (max-width:640px){ .fx-tape{ width:7px; background-size:100% 100px, 60% 10px; } .fx-tape-tab{ right:7px; } .fx-tape-tab::after{ right:-7px; width:7px; } }

/* ---- the steps are a fence: three posts, and a panel goes up between two
   posts as each step is done, board by board. ----------------------------- */
.step i{ border-radius:3px 3px 2px 2px; position:relative; }
.step i::before{ content:""; position:absolute; left:-2px; right:-2px; top:-3px; height:4px; border-radius:2px; background:inherit; filter:brightness(.85); }
.bar{ height:22px; margin:3px 7px 0; border-radius:2px; overflow:hidden;
  background:
    linear-gradient(var(--fill-2), var(--fill-2)) 0 4px / 100% 3px no-repeat,
    linear-gradient(var(--fill-2), var(--fill-2)) 0 15px / 100% 3px no-repeat; }
.bar::after{ transform:none; border-radius:1px; transition:none;
  background:repeating-linear-gradient(90deg, var(--secondary) 0 7px, var(--secondary-strong) 7px 8px, transparent 8px 9px);
  clip-path:inset(0 100% 0 0); }
.bar.done::after{ clip-path:inset(0 0 0 0); transition:clip-path .9s steps(10, end); }

/* ---- writing the proposal: the bar fills board by board ------------------- */
.progress-track{ height:14px; border-radius:3px;
  background:
    linear-gradient(var(--fill-2), var(--fill-2)) 0 3px / 100% 2px no-repeat,
    linear-gradient(var(--fill-2), var(--fill-2)) 0 9px / 100% 2px no-repeat; }
.progress-fill{ border-radius:2px;
  background:repeating-linear-gradient(90deg, var(--primary) 0 9px, var(--primary-strong) 9px 10px, transparent 10px 12px); }
.progress.failed .progress-fill{ background:repeating-linear-gradient(90deg, var(--danger) 0 9px, transparent 9px 12px); }

/* ---- the card: a hairline edge, so it reads as a sheet of paper ----------- */
.card{ box-shadow:var(--sh-3), 0 0 0 1px var(--line); }

/* ---- hover, with a mouse: things you can press lift a little --------------- */
.ap-theme, .ap-bg, .hs-hit, .access-row, .saved-list > *{
  transition:transform .25s var(--glide), box-shadow .25s var(--glide), background var(--mid) var(--ease);
}
html.fx-mouse .ap-theme:hover, html.fx-mouse .ap-bg:hover, html.fx-mouse .hs-hit:hover,
html.fx-mouse .saved-list > *:hover{
  transform:translateY(-2px); box-shadow:var(--sh-lift);
}
/* Text links draw their underline in, rather than having one sitting there. */
.linkbtn{ background-image:linear-gradient(currentColor, currentColor); background-repeat:no-repeat;
  background-size:0% 1px; background-position:0 100%; transition:background-size .3s var(--glide); }
html.fx-mouse .linkbtn:hover{ background-size:100% 1px; }

/* ---- a press: a brief wash of colour where the finger lands ---------------
   Light only. The button never moves or shrinks under a thumb. */
.cta, .pill, .mode, .addrow, .ap-chip, .ap-seg, .themebtn, .accessbtn, .pdfin-find, .pdfin-open,
.greenlight, .pk-trigger, .fxd-btn, .ap-theme, .ap-bg, .hs-hit{
  position:relative; overflow:hidden; isolation:isolate;
}
.fx-ripple{
  position:absolute; border-radius:50%; pointer-events:none; z-index:-1;
  width:var(--rs); height:var(--rs); left:var(--rl); top:var(--rt);
  background:currentColor; opacity:.12; transform:scale(0);
  animation:fx-ripple .5s var(--glide) forwards;
}
@keyframes fx-ripple{ to{ transform:scale(1); opacity:0; } }

/* Buttons: a real shadow under a filled one, a little deeper on hover. */
.cta:not(.ghost):not(:disabled){ box-shadow:var(--sh-1); transition:background var(--mid) var(--ease), box-shadow .25s var(--glide); }
html.fx-mouse .cta:not(.ghost):not(:disabled):hover{ box-shadow:var(--sh-lift); }

/* ---- fields: a clean ring on focus, and the label takes the colour -------- */
input[type=text]:focus, input[type=email]:focus, input[type=tel]:focus, input[type=number]:focus,
input[type=search]:focus, textarea:focus, .pk-trigger[aria-expanded="true"]{
  box-shadow:0 0 0 2px var(--card), 0 0 0 4px color-mix(in srgb, var(--primary) 55%, transparent);
}
input, textarea{ transition:background var(--mid) var(--ease), box-shadow .2s var(--glide); }
.lbl{ transition:color .2s var(--glide); }
.lbl:has(+ input:focus), .lbl:has(+ textarea:focus), .lbl:has(+ .pk-native + .pk-trigger[aria-expanded="true"]){
  color:var(--primary-deep);
}

/* Switches instead of tick boxes. */
.toggle input[type=checkbox], .access-owner input[type=checkbox]{
  -webkit-appearance:none; appearance:none; flex:none; margin:0; cursor:pointer;
  width:44px; height:26px; border-radius:999px; position:relative;
  background:var(--fill-2); box-shadow:inset 0 0 0 1px var(--line);
  transition:background .2s var(--glide);
}
.toggle input[type=checkbox]::before, .access-owner input[type=checkbox]::before{
  content:""; position:absolute; top:3px; left:3px; width:20px; height:20px; border-radius:50%;
  background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.22), 0 0 0 .5px rgba(0,0,0,.06);
  transition:transform .3s var(--spring);
}
.toggle input[type=checkbox]:checked, .access-owner input[type=checkbox]:checked{ background:var(--primary); }
.toggle input[type=checkbox]:checked::before, .access-owner input[type=checkbox]:checked::before{ transform:translateX(18px); }
.toggle input[type=checkbox]:focus-visible, .access-owner input[type=checkbox]:focus-visible{ outline:2px solid var(--primary); outline-offset:3px; }

/* A slider: a plain track and a knob in the theme's colour. */
input[type=range]{ -webkit-appearance:none; appearance:none; height:26px; background:transparent; cursor:pointer; flex:1; min-width:90px; }
input[type=range]::-webkit-slider-runnable-track{ height:4px; border-radius:999px; background:var(--fill-2); }
input[type=range]::-moz-range-track{ height:4px; border-radius:999px; background:var(--fill-2); }
input[type=range]::-moz-range-progress{ height:4px; border-radius:999px; background:var(--primary); }
input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; width:22px; height:22px; margin-top:-9px; border-radius:50%;
  background:#fff; border:0; box-shadow:0 1px 4px rgba(0,0,0,.3), 0 0 0 1px var(--line), inset 0 0 0 6px var(--primary); }
input[type=range]::-moz-range-thumb{ width:22px; height:22px; border-radius:50%; background:#fff; border:6px solid var(--primary); box-sizing:border-box; }

/* The button inside a file input, in the app's own style. */
input[type=file]::file-selector-button{
  font:inherit; font-weight:700; font-size:13px; border:0; cursor:pointer; margin-right:12px;
  padding:10px 16px; border-radius:var(--r-pill); color:var(--on-primary); background:var(--primary);
  transition:background var(--mid) var(--ease);
}
input[type=file]::file-selector-button:hover{ background:var(--primary-strong); }

/* ---- the finished step: the tick arrives ------------------------------------ */
.tick{ animation:fx-tick .5s var(--spring) both .1s; }
@keyframes fx-tick{ from{ transform:scale(.6); opacity:0; } }

/* A message that just changed fades in, so the eye goes to it. */
.fx-said{ animation:fx-said .3s var(--glide); }
@keyframes fx-said{ from{ opacity:.25; } }

/* ---- reveal on scroll: what arrives in view rises a few pixels -------------- */
.pane, .pages, .settings-body, .access-body, .ap-grid, .ap-bgs, .cost-rows, #calcRuns, .hs-results{ perspective:1100px; }
/* Like a board on a hinge: it swings up into place as it arrives. */
.fx-pending{ opacity:.001; translate:0 14px; rotate:x 48deg; transform-origin:50% 100%; }
.fx-shown{ transform-origin:50% 100%; transition:opacity .45s var(--glide), translate .6s var(--spring), rotate .7s var(--spring); transition-delay:var(--fx-d,0ms); }
/* The pane animation in styles.css holds opacity at 1 once it has run, which
   would win over the line above; this lets the reveal own it. */
.pane:not(.hidden) > .fx-pending, .pane:not(.hidden) > .fx-shown, .pane:not(.hidden) > .fx-done{ animation:none; }

/* ---- moving to the next step: it turns in like a page -------------------------- */
.card{ perspective:1600px; }
.pane:not(.hidden){ animation:fx-turn .6s var(--spring) both; transform-origin:0% 50%; }
@keyframes fx-turn{ from{ opacity:0; transform:rotateY(-14deg) translateX(18px); } }

/* ---- the picture at the top drifts slowly, and pulls back as the page goes up ---- */
body::before, .fx-film{ transform-origin:50% 35%; animation:fx-drift 38s ease-in-out infinite alternate; scale:var(--fx-zoom, 1); }
@keyframes fx-drift{ from{ transform:scale(1.02) translate3d(0,0,0); } to{ transform:scale(1.09) translate3d(-1.5%,1%,0); } }
/* The garden film, behind the same wash as a picture. */
.fx-film{ position:fixed; left:0; top:0; width:100%; height:var(--app-bg-height, min(46vh,430px)); object-fit:cover; z-index:-2; pointer-events:none; }
html.bg-film body::before{ background-image:var(--app-bg-overlay); }
.ap-bg.film{ position:relative; }
.ap-film-badge{ position:absolute; left:6px; top:6px; display:inline-flex; gap:4px; align-items:center; font-size:10px; font-weight:800;
  letter-spacing:.06em; text-transform:uppercase; background:rgba(0,0,0,.6); color:#fff; padding:3px 6px; border-radius:4px; }
.ap-film-badge svg.ic{ width:12px; height:12px; display:inline-block; stroke:#fff; }

/* ---- the proposal is ready: a handful of boards tumble down ----------------------- */
.fx-boards{ position:fixed; inset:0; z-index:60; pointer-events:none; overflow:hidden; }
.fx-boards i{ position:absolute; top:-40px; left:var(--x); width:8px; height:30px; border-radius:1px 1px 0 0;
  background:linear-gradient(90deg, var(--c1) 0 70%, var(--c2) 70%); box-shadow:0 2px 3px rgba(0,0,0,.15);
  animation:fx-fall var(--t) cubic-bezier(.3,.1,.6,1) var(--d) both; }
@keyframes fx-fall{
  0%{ transform:translate3d(0,0,0) rotate(0); opacity:1; }
  85%{ opacity:1; }
  100%{ transform:translate3d(var(--dx), 112vh, 0) rotate(var(--r)) rotateY(var(--ry)); opacity:0; }
}

/* ---- first open: a fence goes up while the app gets ready ------------------------- */
.fx-splash{ position:fixed; inset:0; z-index:3000; pointer-events:none; display:grid; place-items:center; align-content:center; gap:22px;
  background:var(--bg); transition:opacity .45s var(--glide), transform .55s var(--glide);
  animation:fx-splash-safety .3s linear 4s forwards; }
html.no-splash .fx-splash{ display:none; }
.fx-splash.out{ opacity:0; transform:scale(1.04); }
@keyframes fx-splash-safety{ to{ opacity:0; visibility:hidden; } }
.fx-splash-fence{ position:relative; width:168px; height:96px; display:flex; align-items:flex-end; gap:4px; padding:0 14px; }
.fx-splash-fence::before, .fx-splash-fence::after{ content:""; position:absolute; left:6px; right:6px; height:5px; background:var(--secondary-strong); border-radius:2px; transform:scaleX(0); transform-origin:left; animation:fx-rail .35s var(--glide) forwards .25s; }
.fx-splash-fence::before{ top:26px; } .fx-splash-fence::after{ bottom:16px; }
.fx-splash-fence .p{ position:absolute; bottom:0; width:13px; height:100%; background:var(--primary); border-radius:3px 3px 1px 1px; transform:scaleY(0); transform-origin:bottom; animation:fx-post .35s var(--spring) forwards; }
.fx-splash-fence .p.l{ left:0; } .fx-splash-fence .p.r{ right:0; animation-delay:.1s; }
.fx-splash-fence b{ flex:1; height:88%; position:relative; z-index:1; background:linear-gradient(90deg, var(--secondary) 0 72%, var(--secondary-strong) 72%); border-radius:2px 2px 0 0;
  opacity:0; transform:translateY(-70px) rotate(8deg); animation:fx-board-drop .42s var(--spring) forwards; animation-delay:calc(.42s + var(--i) * 70ms); }
.fx-splash-fence b:nth-child(odd){ transform:translateY(-70px) rotate(-7deg); }
@keyframes fx-post{ to{ transform:scaleY(1); } }
@keyframes fx-rail{ to{ transform:scaleX(1); } }
@keyframes fx-board-drop{ to{ opacity:1; transform:none; } }
@property --fx-cm{ syntax:'<integer>'; inherits:false; initial-value:0; }
.fx-splash-tape{ font:800 12px/1 var(--sans); letter-spacing:.14em; text-transform:uppercase; color:var(--soft); display:flex; gap:10px; align-items:center; }
.fx-splash-tape i{ display:block; width:150px; height:10px; border-radius:2px; background-color:var(--secondary);
  background-image:linear-gradient(90deg, rgba(0,0,0,.45) 0 1px, transparent 1px); background-size:10px 100%;
  clip-path:inset(0 100% 0 0); animation:fx-tape-out 1s var(--glide) forwards .2s; }
.fx-splash-tape span{ --fx-cm:0; counter-reset:cm var(--fx-cm); animation:fx-count 1s var(--glide) forwards .2s; font-variant-numeric:tabular-nums; min-width:52px; }
.fx-splash-tape span::after{ content:counter(cm) " cm"; }
@keyframes fx-tape-out{ to{ clip-path:inset(0 0 0 0); } }
@keyframes fx-count{ to{ --fx-cm:180; } }

/* ---- screens that open over the app ------------------------------------------ */
.overlay:not(.hidden){ animation:fx-sheet .38s var(--glide) both; }
@keyframes fx-sheet{ from{ opacity:0; transform:translateY(16px); } }
.lockpane:not(.hidden) .lockcard{ animation:fx-sheet .45s var(--glide) both .05s; }

/* Day and night: the new look spreads out in a circle from the button. */
::view-transition-old(root), ::view-transition-new(root){ animation:none; mix-blend-mode:normal; }
::view-transition-new(root){ animation:fx-circle .55s var(--glide); }
@keyframes fx-circle{
  from{ clip-path:circle(0 at var(--vt-x,50%) var(--vt-y,0)); }
  to{ clip-path:circle(150vmax at var(--vt-x,50%) var(--vt-y,0)); }
}

/* ===========================================================================
   Pickers (public/picker.js): every <select> becomes this. The real select
   stays in the page underneath and keeps the value, so everything that reads
   it, HubSpot's exact values included, is unchanged.
   ========================================================================= */
.pk-native{ position:absolute !important; width:1px !important; height:1px !important; opacity:0 !important; padding:0 !important; border:0 !important; min-width:0 !important;
  pointer-events:none !important; overflow:hidden !important; clip-path:inset(50%) !important; margin:0 !important; }
.pk-trigger{
  display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; text-align:left;
  border:0; cursor:pointer; font:inherit; font-size:15px; color:var(--ink);
  background:var(--fill); border-radius:var(--r-sm); padding:13px 14px; min-height:48px;
  transition:background var(--mid) var(--ease), box-shadow .2s var(--glide);
}
.pk-trigger:hover{ background:var(--fill-2); }
.pk-trigger:disabled{ opacity:.55; cursor:default; }
.pk-trigger .pk-label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pk-trigger .pk-label.pk-empty{ color:var(--faint); }
.pk-trigger svg{ flex:none; width:18px; height:18px; color:var(--soft); transition:transform .25s var(--glide); }
.pk-trigger[aria-expanded="true"] svg{ transform:rotate(180deg); }
.pk-trigger[aria-expanded="true"]{ background:var(--card); }
.calc-field .pk-trigger, .m-fields .pk-trigger{ font-size:14px; padding:10px 12px; min-height:42px; }
.m-fields .pk-trigger{ width:auto; min-width:84px; }

.pk-backdrop{ position:fixed; inset:0; z-index:1100; background:rgba(0,0,0,.36); animation:fx-fade-in .25s var(--glide) both; }
.pk-backdrop.pk-light{ background:transparent; }
.pk-backdrop.pk-out{ animation:fx-fade-out .2s var(--glide) both; }
@keyframes fx-fade-in{ from{ opacity:0; } }
@keyframes fx-fade-out{ to{ opacity:0; } }

.pk-panel{ position:fixed; z-index:1101; background:var(--card); color:var(--ink);
  box-shadow:var(--sh-pop), 0 0 0 1px var(--line); display:flex; flex-direction:column; overflow:hidden; outline:0; }
/* On a phone: a sheet from the bottom, with a handle, big rows for a thumb. */
.pk-panel.pk-sheet{ left:0; right:0; bottom:0; max-height:72vh; border-radius:18px 18px 0 0;
  padding:8px 8px calc(12px + env(safe-area-inset-bottom)); animation:fx-sheet-up .42s var(--spring) both; }
.pk-panel.pk-sheet.pk-out{ animation:fx-sheet-down .22s var(--glide) both; }
@keyframes fx-sheet-up{ from{ transform:translateY(100%); } }
@keyframes fx-sheet-down{ to{ transform:translateY(100%); } }
.pk-handle{ width:36px; height:5px; border-radius:5px; background:var(--fill-2); margin:2px auto 10px; flex:none; }
.pk-title{ font-size:11px; font-weight:800; letter-spacing:.1em; text-transform:uppercase; color:var(--soft); padding:0 12px 8px; }
/* With a mouse: a popover against the field. */
.pk-panel.pk-pop{ border-radius:12px; padding:5px; max-height:340px; transform-origin:var(--pk-origin, top center);
  animation:fx-pop-open .18s var(--glide) both; }
.pk-panel.pk-pop.pk-out{ animation:fx-fade-out .12s var(--glide) both; }
@keyframes fx-pop-open{ from{ opacity:0; transform:scale(.98) translateY(-4px); } }

.pk-search{ margin:2px 4px 6px; flex:none; position:relative; }
.pk-search input{ width:100%; -webkit-appearance:none; appearance:none; border:0; font:inherit; font-size:15px; color:var(--ink);
  padding:11px 14px 11px 38px; border-radius:var(--r-sm); background:var(--fill); }
.pk-search input:focus{ outline:0; background:var(--fill-2); box-shadow:none; }
.pk-search input::placeholder{ color:var(--faint); }
.pk-search svg{ position:absolute; left:12px; top:50%; width:16px; height:16px; transform:translateY(-50%); color:var(--faint); pointer-events:none; }
.pk-list{ list-style:none; margin:0; padding:0; overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }
.pk-group{ font-size:10.5px; font-weight:800; letter-spacing:.1em; text-transform:uppercase; color:var(--faint); padding:12px 12px 4px; }
.pk-opt{ display:flex; align-items:center; gap:10px; padding:10px 12px; border-radius:8px; cursor:pointer;
  font-size:15px; user-select:none; position:relative; transition:background .12s linear;
  animation:fx-opt-in .34s var(--glide) both; animation-delay:calc(var(--i, 0) * 16ms + 60ms); }
@keyframes fx-opt-in{ from{ opacity:0; transform:translateY(7px); } }
.pk-sheet .pk-opt{ padding:14px 12px; font-size:16px; border-radius:10px; }
.pk-sheet .pk-opt + .pk-opt::before{ content:""; position:absolute; left:40px; right:12px; top:0; height:1px; background:var(--line); }
.pk-opt .pk-check{ width:18px; height:18px; flex:none; color:var(--primary); visibility:hidden; }
.pk-opt[aria-selected="true"]{ font-weight:700; }
.pk-opt[aria-selected="true"] .pk-check{ visibility:visible; }
.pk-opt.pk-active{ background:var(--fill); }
.pk-opt[aria-disabled="true"]{ opacity:.45; cursor:default; }
.pk-none{ padding:16px 12px; color:var(--faint); font-size:14px; }

/* ===========================================================================
   Dialogs (public/dialog.js), instead of the browser's own confirm box.
   ========================================================================= */
.fxd-back{ position:fixed; inset:0; z-index:1200; display:flex; align-items:center; justify-content:center; padding:20px;
  background:rgba(0,0,0,.4); animation:fx-fade-in .2s var(--glide) both; }
.fxd-back.fxd-out{ animation:fx-fade-out .16s var(--glide) both; }
.fxd{ width:min(380px,100%); background:var(--card); color:var(--ink); border-radius:18px; padding:22px 20px 16px;
  box-shadow:var(--sh-pop), 0 0 0 1px var(--line); animation:fx-dialog-in .3s var(--spring) both; }
.fxd-out .fxd{ animation:fx-fade-out .14s var(--glide) both; }
@keyframes fx-dialog-in{ from{ opacity:0; transform:scale(.96); } }
.fxd-icon{ width:40px; height:40px; margin:0 0 12px; border-radius:12px; display:grid; place-items:center;
  background:var(--primary-100); color:var(--primary-deep); }
.fxd.fxd-danger .fxd-icon{ background:var(--danger-100); color:var(--danger-strong); }
.fxd-icon svg{ width:22px; height:22px; }
.fxd h3{ margin:0 0 6px; font-family:var(--serif); font-weight:500; font-size:20px; letter-spacing:-.01em; }
.fxd p{ margin:0 0 18px; color:var(--soft); font-size:14.5px; line-height:1.55; }
.fxd-acts{ display:flex; gap:8px; justify-content:flex-end; }
.fxd-btn{ border:0; cursor:pointer; font:inherit; font-weight:700; font-size:14.5px; padding:12px 18px; border-radius:var(--r-sm);
  background:var(--fill); color:var(--ink); transition:background var(--mid) var(--ease); }
.fxd-btn:hover{ background:var(--fill-2); }
.fxd-btn.fxd-ok{ background:var(--primary); color:var(--on-primary); }
.fxd-btn.fxd-ok:hover{ background:var(--primary-strong); }
.fxd.fxd-danger .fxd-btn.fxd-ok{ background:var(--danger-btn); color:var(--on-danger); }
.fxd.fxd-danger .fxd-btn.fxd-ok:hover{ background:var(--danger-btn-hover); }
@media (max-width:420px){ .fxd-acts{ flex-direction:column-reverse; } .fxd-btn{ width:100%; padding:14px; } }

/* ===========================================================================
   Calm: Effects set to Calm in Appearance, or the phone asks for less motion.
   Nothing slides, rises or spreads; everything else stays.
   ========================================================================= */
html.fx-calm .fx-pending{ opacity:1; translate:none; rotate:none; }
html.fx-calm body::before, html.fx-calm .fx-film, html.fx-calm .pane:not(.hidden), html.fx-calm .pk-opt{ animation:none !important; scale:none; }
html.fx-calm .fx-boards{ display:none; }
html.fx-calm .overlay:not(.hidden), html.fx-calm .lockcard, html.fx-calm .tick, html.fx-calm .fx-said,
html.fx-calm .pk-panel, html.fx-calm .fxd{ animation:none !important; }
html.fx-calm ::view-transition-new(root){ animation:none; }
html.fx-calm .bar.done::after{ transition:none; }
@media (prefers-reduced-motion: reduce){
  .fx-pending{ opacity:1; translate:none; rotate:none; }
  .overlay:not(.hidden), .lockcard, .tick, .fx-said, .pk-panel, .fxd, body::before, .fx-film, .pane:not(.hidden), .pk-opt{ animation:none !important; }
  body::before, .fx-film{ scale:none; }
  .fx-boards, .fx-splash{ display:none; }
  .bar.done::after{ transition:none; }
}
