/* Effects: motion that makes the shell feel like a game client. Two textures, one timing: a phosphor CRT in the
   dark (scanlines, glow, flicker) and a green-bar printer in the light (paper feed, type strike).

   html[data-fx]        full · subtle (fades only, no movement) · off
   html[data-fx-theme]  crt · paper (set by fx.js from the theme in use)

   Only transform, opacity and clip-path move, and nothing here sits in front of a click: entrances run while
   the page is already usable. */

:root { --fx-out: cubic-bezier(.2, .7, .2, 1); --fx-step: 28ms; }

/* --- Page transitions: the old page is scanned away, the new one boots in, block by block --------------------- */

[data-fx="full"][data-fx-theme="crt"] .fx-enter [data-fx-i] { animation: fx-in-crt .28s var(--fx-out) both; animation-delay: calc(var(--fx-i) * var(--fx-step)); }
[data-fx="full"][data-fx-theme="paper"] .fx-enter [data-fx-i] { animation: fx-in-paper .3s var(--fx-out) both; animation-delay: calc(var(--fx-i) * var(--fx-step)); }
[data-fx="subtle"] .fx-enter [data-fx-i] { animation: fx-fade .2s ease-out both; animation-delay: calc(var(--fx-i) * 14ms); }
@keyframes fx-in-crt {
  from { opacity: 0; transform: translate(var(--fx-dx, 0), 5px); }
  35% { opacity: .9; }
  50% { opacity: .45; }
  to { opacity: 1; transform: none; }
}
@keyframes fx-in-paper {
  from { opacity: 0; transform: translate(var(--fx-dx, 0), -7px); clip-path: inset(0 0 100% 0); }
  to { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }
}
@keyframes fx-fade { from { opacity: 0; } }

/* The page's title types itself in. */
[data-fx="full"] .fx-enter .frame h1 { animation: fx-type .34s steps(16, end) both .04s; }
@keyframes fx-type { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }

/* Leaving: a scanline (or the print head) sweeps the pane. */
.fx-scan { position: absolute; left: 0; right: 0; pointer-events: none; z-index: 4; overflow: hidden; }
.fx-scan::before {
  content: ""; position: absolute; left: 0; right: 0; top: -40px; height: 40px;
  background: linear-gradient(transparent, color-mix(in srgb, var(--accent) 16%, transparent) 70%, var(--accent));
  animation: fx-sweep .32s cubic-bezier(.4, 0, .6, 1) forwards;
}
[data-fx-theme="crt"] .fx-scan::before { filter: drop-shadow(0 0 4px var(--accent)); }
[data-fx-theme="paper"] .fx-scan::before { height: 14px; top: -14px; background: linear-gradient(transparent, color-mix(in srgb, var(--ink) 22%, transparent)); }
@keyframes fx-sweep { to { transform: translateY(var(--fx-h, 600px)); opacity: .2; } }

/* The progress bar is a carrier: a bright head with a trail, shimmering while it waits, fading when it lands. */
.pane-progress { background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 60%, transparent) 70%, var(--accent)); transition: width .3s, opacity .25s; }
.pane-progress::after { content: ""; position: absolute; right: -1px; top: -1px; width: 5px; height: 4px; background: var(--accent); box-shadow: 0 0 calc(var(--glow) * 2 + 2px) var(--accent); }
[data-fx="full"] .pane.loading .pane-progress::after { animation: blink .5s steps(2) infinite; }

/* --- Clicks ------------------------------------------------------------------------------------------------ */

[data-fx="full"] :is(button, .btn, .toggle, .cmd-act, .ss-chip, .a-chip, .bd-slot, .bd-recipe, .icon-btn, .rail-items a):not(:disabled) { transition: transform .07s ease-out, border-color .15s, background-color .15s, filter .15s, box-shadow .15s; }
[data-fx="full"] :is(button, .btn, .toggle, .cmd-act, .ss-chip, .a-chip, .bd-slot, .bd-recipe, .icon-btn, .rail-items a):active:not(:disabled) { transform: translateY(1px) scale(.985); }

/* A ring pulses out from where you clicked. */
.fx-ping { position: fixed; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; pointer-events: none; z-index: 9000;
  border: 1px solid var(--accent); animation: fx-ping .4s ease-out forwards; }
[data-fx-theme="crt"] .fx-ping { box-shadow: 0 0 6px var(--accent); }
@keyframes fx-ping { from { transform: scale(.6); opacity: .85; } to { transform: scale(5); opacity: 0; } }

/* Sending an order: the button carries a transmit bar; then an ACK stamp, or the panel shakes off a refusal. */
.fx-tx { position: relative; overflow: hidden; }
.fx-tx::after { content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 35%; background: var(--accent); box-shadow: 0 0 var(--glow) var(--accent); animation: fx-tx .55s linear infinite; }
@keyframes fx-tx { from { transform: translateX(-100%); } to { transform: translateX(300%); } }
.fx-stamp {
  position: fixed; z-index: 9001; pointer-events: none; transform: translate(-50%, -50%) rotate(-7deg);
  font: 600 15px/1 var(--font); letter-spacing: .2em; padding: 5px 9px 4px 11px; white-space: nowrap;
  color: var(--accent); border: 2px solid var(--accent); background: color-mix(in srgb, var(--paper) 82%, transparent);
  animation: fx-stamp 1.1s var(--fx-out) forwards;
}
.fx-stamp small { font-size: 10px; letter-spacing: .06em; margin-left: 6px; font-weight: 500; }
[data-fx-theme="crt"] .fx-stamp { text-shadow: 0 0 var(--glow) var(--accent); box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 50%, transparent); }
[data-fx="subtle"] .fx-stamp { animation-name: fx-stamp-soft; }
@keyframes fx-stamp { 0% { opacity: 0; transform: translate(-50%, -50%) rotate(-7deg) scale(1.7); } 14% { opacity: 1; transform: translate(-50%, -50%) rotate(-7deg) scale(1); } 75% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%, -60%) rotate(-7deg); } }
@keyframes fx-stamp-soft { 0%, 100% { opacity: 0; } 15%, 75% { opacity: 1; } }
[data-fx="full"] .fx-shake { animation: fx-shake .34s ease-out; }
[data-fx="subtle"] .fx-shake { box-shadow: inset 0 0 0 1px var(--alert); }
@keyframes fx-shake { 20% { transform: translateX(-5px); } 40% { transform: translateX(4px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(2px); } }
[data-fx="full"] .fx-typed { animation: fx-type .4s steps(22, end) both; }

/* A highlight that slides from the old choice to the new one: tabs, chips, the hot-switch strip. */
.fx-marker { position: fixed; z-index: 60; pointer-events: none; border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
  transition: left .22s var(--fx-out), top .22s var(--fx-out), width .22s var(--fx-out), height .22s var(--fx-out), opacity .14s; }
[data-fx-theme="crt"] .fx-marker { box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 55%, transparent); }

/* Things that open unroll. */
[data-fx="full"] .fx-open[open] > :not(summary),
[data-fx="full"] :is(.cmd-detail, .bd-detail, .o-card, .result):not([hidden]) { animation: fx-unroll .2s var(--fx-out); }
[data-fx="subtle"] .fx-open[open] > :not(summary) { animation: fx-fade .18s; }
@keyframes fx-unroll { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
[data-fx="full"] dialog.palette[open], [data-fx="full"] dialog.ax-confirm[open] { animation: fx-pop .16s var(--fx-out); }
[data-fx="full"] dialog.palette[open]::backdrop { animation: fx-fade .2s; }
@keyframes fx-pop { from { opacity: 0; transform: translateY(-8px) scale(.98); } }

/* Hovering a card: phosphor bloom in the dark. */
[data-fx="full"][data-fx-theme="crt"] :is(.st-card, .body-card, .a-ship, .a-order, .bd-slot, .bd-recipe, .cmd-act, .ss-chip, .a-chip, .a-letter):hover:not(:disabled) { filter: drop-shadow(0 0 3px color-mix(in srgb, var(--accent) 45%, transparent)); }

/* --- Live data ----------------------------------------------------------------------------------------------- */

/* A number that went up or down glows its way to the new value. */
.fx-up, .fx-down { transition: color 1.2s, text-shadow 1.2s; }
.fx-up.fx-lit { color: var(--accent) !important; }
.fx-down.fx-lit { color: var(--alert) !important; }
[data-fx-theme="crt"] .fx-up.fx-lit { text-shadow: 0 0 6px var(--accent); }
[data-fx-theme="crt"] .fx-down.fx-lit { text-shadow: 0 0 6px var(--alert); }

/* A refreshed region gets a faint scan pass. */
.fx-sweep { position: fixed; pointer-events: none; z-index: 50; overflow: hidden; }
.fx-sweep::before { content: ""; position: absolute; left: 0; right: 0; top: -24px; height: 24px;
  background: linear-gradient(transparent, color-mix(in srgb, var(--accent) 10%, transparent) 80%, color-mix(in srgb, var(--accent) 45%, transparent));
  animation: fx-sweep .5s linear forwards; }

/* New events slide in under a blinking cursor. */
[data-fx="full"] ol.feed li.fresh { position: relative; animation: fx-feed .26s var(--fx-out), blip 1.6s ease-out; }
[data-fx="full"] ol.feed li.fresh::before { content: "▌"; position: absolute; left: -1.7ch; color: var(--accent); animation: fx-cursor 1s steps(2, jump-none) forwards; }
@keyframes fx-feed { from { opacity: 0; transform: translateX(-10px); clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-cursor { 0%, 49% { opacity: 1; } 50%, 74% { opacity: 0; } 75% { opacity: 1; } 100% { opacity: 0; } }

/* The tick counter flips. */
[data-fx="full"] .clock.ticked [data-f="tick"] { animation: fx-flip .38s var(--fx-out); }
@keyframes fx-flip { from { transform: perspective(160px) rotateX(-85deg); opacity: .2; } to { transform: none; } }

/* Switching theme: the tube flickers, or the paper settles. */
[data-fx="full"] .fx-theme-swap { animation: fx-flicker .38s steps(1, end); }
@keyframes fx-flicker { 0% { opacity: .25; } 20% { opacity: .9; } 35% { opacity: .5; } 55% { opacity: 1; } 70% { opacity: .8; } 100% { opacity: 1; } }

/* --- Maps and building ----------------------------------------------------------------------------------- */

/* A targeting reticle closes in on what you click on a map. */
.fx-reticle { position: fixed; z-index: 55; pointer-events: none; transform: translate(-50%, -50%);
  transition: width .24s var(--fx-out), height .24s var(--fx-out), opacity .3s; }
.fx-reticle i { position: absolute; width: 7px; height: 7px; border: 0 solid var(--accent); }
.fx-reticle i:nth-child(1) { left: 0; top: 0; border-width: 1.5px 0 0 1.5px; }
.fx-reticle i:nth-child(2) { right: 0; top: 0; border-width: 1.5px 1.5px 0 0; }
.fx-reticle i:nth-child(3) { left: 0; bottom: 0; border-width: 0 0 1.5px 1.5px; }
.fx-reticle i:nth-child(4) { right: 0; bottom: 0; border-width: 0 1.5px 1.5px 0; }
[data-fx-theme="crt"] .fx-reticle i { filter: drop-shadow(0 0 2px var(--accent)); }

/* A new facility materializes in its slot as a wireframe that fills in; a started recipe's facility pulses. */
[data-fx="full"] .fx-built .bd-slot.building { animation: fx-materialize 1.1s var(--fx-out); }
@keyframes fx-materialize {
  0% { clip-path: inset(0 0 100% 0); outline: 1px dashed var(--accent); outline-offset: -1px; opacity: .3; }
  55% { clip-path: inset(0 0 0 0); opacity: .7; }
  70% { opacity: .45; }
  100% { clip-path: inset(0 0 0 0); outline-color: transparent; opacity: 1; }
}
[data-fx="full"] .fx-built .bd-slot.full.on { animation: fx-pulse-ring 1s ease-out 2; }
[data-fx="full"] .fx-built .bd-arrow { display: inline-block; animation: fx-arrow .5s ease-in-out 4; }
@keyframes fx-pulse-ring { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent); } to { box-shadow: 0 0 0 10px transparent; } }
@keyframes fx-arrow { 50% { transform: translateX(4px); color: var(--accent); } }

/* --- Toasts: what matters, as it happens ---------------------------------------------------------------------- */

.fx-toasts { position: fixed; right: calc(var(--dock-w) + 16px); bottom: calc(var(--status-h) + 12px); z-index: 80; display: grid; gap: 8px; width: min(340px, calc(100vw - 32px)); pointer-events: none; }
.fx-toast {
  pointer-events: auto; display: grid; grid-template-columns: 2.2ch minmax(0, 1fr) auto; gap: 2px 10px; align-items: baseline;
  padding: 8px 10px 8px 12px; font: 13px/1.4 var(--font); color: var(--ink); text-align: left; cursor: pointer;
  background: var(--paper); border: 1px solid var(--rule); border-left: 3px solid var(--accent);
  box-shadow: 0 6px 20px color-mix(in srgb, #000 22%, transparent);
}
.fx-toast.bad { border-left-color: var(--alert); }
.fx-toast i { font-style: normal; color: var(--accent); grid-row: span 2; }
.fx-toast.bad i { color: var(--alert); }
.fx-toast b { font-size: 11px; letter-spacing: .12em; }
.fx-toast .fx-t-x { grid-row: span 2; align-self: start; color: var(--dim); background: none; border: none; font: inherit; cursor: pointer; padding: 0 2px; }
.fx-toast .fx-t-x:hover { color: var(--ink); }
.fx-toast span { grid-column: 2; overflow-wrap: anywhere; }
.fx-toast:hover { border-color: var(--accent); }
[data-fx-theme="crt"] .fx-toast { box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 22%, transparent); }
[data-fx-theme="crt"] .fx-toast.bad { box-shadow: 0 0 10px color-mix(in srgb, var(--alert) 30%, transparent); }
[data-fx="full"][data-fx-theme="crt"] .fx-toast { animation: fx-toast-crt .3s var(--fx-out); }
[data-fx="full"][data-fx-theme="paper"] .fx-toast { animation: fx-in-paper .3s var(--fx-out); }
[data-fx="subtle"] .fx-toast { animation: fx-fade .2s; }
.fx-toast.gone { opacity: 0; transform: translateX(16px); transition: opacity .2s, transform .2s; }
@keyframes fx-toast-crt { from { opacity: 0; transform: translateX(28px); } 60% { opacity: .6; } to { opacity: 1; transform: none; } }
@media (max-width: 1100px) { .fx-toasts { right: 16px; } }
/* Out of the way (fx.js place()): at the top when the corner is busy, a one-line badge after a few seconds or over a
   map, hidden while both places would cover the control you're in. */
.fx-toasts.top { bottom: auto; top: calc(var(--top-h) + 12px); }
.fx-toasts.aside { visibility: hidden; }
.fx-toast.mini:not(:hover):not(:focus-within), .fx-toasts.mini .fx-toast:not(:hover):not(:focus-within) {
  justify-self: end; grid-template-columns: 2.2ch auto auto; padding: 3px 8px; box-shadow: none; max-width: 100%; }
.fx-toast.mini:not(:hover):not(:focus-within) span, .fx-toasts.mini .fx-toast:not(:hover):not(:focus-within) span { display: none; }
.fx-toast.mini:not(:hover):not(:focus-within) i, .fx-toasts.mini .fx-toast:not(:hover):not(:focus-within) i { grid-row: auto; }
.fx-toast.mini:not(:hover):not(:focus-within) .fx-t-x, .fx-toasts.mini .fx-toast:not(:hover):not(:focus-within) .fx-t-x { grid-row: auto; }

/* --- The boot: a terminal cold start, once a session ------------------------------------------------------- */

html.fx-boot body::after { content: ""; position: fixed; inset: 0; z-index: 9998; background: var(--paper); }
.fx-boot-screen {
  position: fixed; inset: 0; z-index: 9999; background: var(--paper); color: var(--ink); cursor: pointer;
  display: grid; place-content: center; font: 14px/1.7 var(--font);
}
.fx-boot-screen pre { margin: 0; background: none; border: none; padding: 0; min-width: min(560px, 90vw); white-space: pre-wrap; font: inherit; color: inherit; max-height: none; }
.fx-boot-screen .ok { color: var(--accent); }
.fx-boot-screen .dim { color: var(--dim); }
.fx-boot-screen .head { letter-spacing: .2em; font-weight: 600; }
.fx-boot-screen .cur { animation: blink .5s steps(2) infinite; color: var(--accent); }
.fx-boot-screen .skip { position: fixed; bottom: 18px; left: 0; right: 0; text-align: center; font-size: 11px; letter-spacing: .1em; color: var(--dim); }
[data-fx-theme="crt"] .fx-boot-screen { text-shadow: 0 0 var(--glow) currentColor; }
[data-fx-theme="crt"] .fx-boot-screen::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(transparent 0 2px, color-mix(in srgb, #000 28%, transparent) 2px 3px); }
[data-fx-theme="paper"] .fx-boot-screen { background-image: repeating-linear-gradient(var(--paper) 0 72px, var(--band) 72px 144px); }
/* Off: the tube collapses to a line and goes out; the paper feeds away upward. */
[data-fx-theme="crt"] .fx-boot-screen.out { animation: fx-tube-off .24s ease-in forwards; }
[data-fx-theme="paper"] .fx-boot-screen.out { animation: fx-paper-out .24s ease-in forwards; }
@keyframes fx-tube-off { 0% { transform: none; filter: brightness(1); } 60% { transform: scale(1, .006); filter: brightness(3); } 100% { transform: scale(0, .006); filter: brightness(3); } }
@keyframes fx-paper-out { to { transform: translateY(-100%); } }

/* --- The settings in the status line --------------------------------------------------------------------- */

.fx-ctl { font: inherit; font-size: inherit; color: var(--dim); background: none; border: none; padding: 0; cursor: pointer; letter-spacing: .04em; }
.fx-ctl b { color: var(--ink); font-weight: 500; }
.fx-ctl:hover b { color: var(--accent); }
