/* ============================================================
   What's New — update log button + modal
   Shared by the dashboard (via base.html) and the login page.
   Kept in its own file so login can use it without pulling in the
   header styles, which would clash with the login layout.
   ============================================================ */

/* ============================================================
   What's New — header button + update log modal
   ============================================================ */
.whatsnew-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.10);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.02));
  font-family: Inter, sans-serif;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
  white-space: nowrap;
  transition: color 200ms ease, border-color 200ms ease;
}
.whatsnew-btn:hover {
  color: #fff;
  border-color: rgba(56, 189, 248, 0.45);
}
.whatsnew-btn svg {
  width: 13px;
  height: 13px;
  fill: currentColor;
  stroke: none;
  opacity: 0.85;
}
/* Unseen release → the whole button glows so it's hard to miss.
   The glow clears the moment the user opens the update log. */
.whatsnew-btn.has-update {
  color: #e0f2fe;
  border-color: rgba(56, 189, 248, 0.65);
  background: linear-gradient(135deg, rgba(56, 189, 248, 0.18), rgba(56, 189, 248, 0.06));
  animation: whatsnew-glow 2s ease-in-out infinite;
}
.whatsnew-btn.has-update svg {
  color: #7dd3fc;
  opacity: 1;
}
@keyframes whatsnew-glow {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(56, 189, 248, 0.45),
                0 0 10px rgba(56, 189, 248, 0.35);
  }
  50% {
    box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.00),
                0 0 20px rgba(56, 189, 248, 0.75);
  }
}
/* Respect users who prefer less motion: keep a steady glow, no pulsing. */
@media (prefers-reduced-motion: reduce) {
  .whatsnew-btn.has-update {
    animation: none;
    box-shadow: 0 0 14px rgba(56, 189, 248, 0.55);
  }
}

/* The old unread dot is no longer used. */
.whatsnew-dot { display: none !important; }

/* Freeze the dashboard behind the update log so only the modal scrolls.
   The JS adds padding equal to the scrollbar width at the same time, so the
   page doesn't shift sideways when the scrollbar is hidden. */
body.wn-lock {
  overflow: hidden;
}

/* ---- Modal ---- */
/* ---- Modal ----
   The backdrop stays in the layout and is toggled via opacity/visibility so it
   can actually animate (display:none can't be transitioned). The modal scales
   and rises in on open, and eases back down on close. */
.wn-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(4, 10, 20, 0);
  backdrop-filter: blur(0px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms ease,
              visibility 0s linear 260ms,
              background-color 320ms ease,
              backdrop-filter 320ms ease;
}
.wn-backdrop.open {
  opacity: 1;
  visibility: visible;
  background: rgba(4, 10, 20, 0.72);
  backdrop-filter: blur(4px);
  transition: opacity 260ms ease,
              visibility 0s linear 0s,
              background-color 320ms ease,
              backdrop-filter 320ms ease;
}

.wn-modal {
  width: 100%;
  max-width: 640px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  background: linear-gradient(150deg, #0b1c30, #0e2138);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  font-family: Inter, sans-serif;

  /* Closed state: slightly small, dropped down, and tilted back. */
  opacity: 0;
  transform: translateY(24px) scale(0.94);
  transition: opacity 220ms ease,
              transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* Open: springs up to full size with an overshoot-free easing curve. */
.wn-backdrop.open .wn-modal {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.wn-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 22px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.wn-eyebrow {
  display: block;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(148, 163, 184, 0.85);
  margin-bottom: 4px;
}
.wn-head h3 {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  color: #fff;
}
.wn-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: 9px;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.10);
  background: rgba(255, 255, 255, 0.05);
  color: rgba(255, 255, 255, 0.75);
}
.wn-close:hover { background: rgba(255, 255, 255, 0.10); color: #fff; }
.wn-close svg {
  width: 15px; height: 15px;
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}

/* Tabs */
.wn-tabs {
  display: flex;
  gap: 4px;
  padding: 12px 22px 0;
}
.wn-tab {
  padding: 8px 14px;
  border: none;
  border-radius: 999px 999px 0 0;
  cursor: pointer;
  background: transparent;
  font-family: Inter, sans-serif;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  border-bottom: 2px solid transparent;
  transition: color 180ms ease, border-color 180ms ease;
}
.wn-tab:hover { color: rgba(255, 255, 255, 0.8); }
.wn-tab.is-active {
  color: #7dd3fc;
  border-bottom-color: #38bdf8;
}

/* Body */
.wn-body {
  padding: 18px 22px 22px;
  overflow-y: auto;
}
.wn-loading {
  margin: 0;
  padding: 20px 0;
  text-align: center;
  color: rgba(255, 255, 255, 0.45);
  font-size: 13px;
}
.wn-release-head {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 4px;
}
.wn-version {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #fff;
}
.wn-current {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  color: #7dd3fc;
  background: rgba(56, 189, 248, 0.12);
  border: 1px solid rgba(56, 189, 248, 0.30);
}
.wn-date {
  margin-left: auto;
  font-size: 11px;
  color: rgba(148, 163, 184, 0.8);
}
.wn-release-title {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.86);
}
.wn-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.wn-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.wn-tag {
  flex-shrink: 0;
  margin-top: 1px;
  min-width: 62px;
  text-align: center;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 4px 7px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.wn-tag--new {
  color: #7dd3fc;
  background: rgba(56, 189, 248, 0.12);
  border-color: rgba(56, 189, 248, 0.28);
}
.wn-tag--improved {
  color: #bbf7d0;
  background: rgba(34, 197, 94, 0.12);
  border-color: rgba(74, 222, 128, 0.26);
}
.wn-tag--fixed {
  color: #fde68a;
  background: rgba(250, 204, 21, 0.12);
  border-color: rgba(250, 204, 21, 0.26);
}
.wn-text {
  font-size: 13px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.78);
}
.wn-sep {
  height: 1px;
  margin: 20px 0;
  background: rgba(255, 255, 255, 0.07);
}

@media (max-width: 1280px) {
  .header-row .whatsnew-btn { font-size: 10px; letter-spacing: 0.08em; }
}
@media (max-width: 900px) {
  /* Keep the header tidy on smaller screens — icon only. */
  .whatsnew-label { display: none; }
}

/* ---- Update log: content entrance ----
   Items cascade in just after the panel lands, so the modal feels alive rather
   than appearing fully-formed. Staggered by position via nth-child.

   This is scoped to `.wn-intro`, a class added only while the modal is opening
   (and removed once the cascade has played). Keying it to `.wn-backdrop.open`
   instead would re-trigger the whole cascade every time the items were replaced
   — e.g. after a tab swap — making the animation appear to run twice. */
.wn-backdrop.open .wn-body.wn-intro .wn-item {
  animation: wn-item-in 380ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(1) { animation-delay: 140ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(2) { animation-delay: 185ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(3) { animation-delay: 230ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(4) { animation-delay: 275ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(5) { animation-delay: 320ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(6) { animation-delay: 365ms; }
.wn-backdrop.open .wn-body.wn-intro .wn-item:nth-child(n+7) { animation-delay: 400ms; }

@keyframes wn-item-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* The release header and title lead the cascade. */
.wn-backdrop.open .wn-body.wn-intro .wn-release-head,
.wn-backdrop.open .wn-body.wn-intro .wn-release-title {
  animation: wn-item-in 380ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
  animation-delay: 90ms;
}

/* Tapping the button should feel responsive. */
.whatsnew-btn:active {
  transform: scale(0.96);
}
.whatsnew-btn {
  transition: color 200ms ease, border-color 200ms ease, transform 120ms ease;
}

/* Honour reduced-motion: show everything immediately, no movement. */
@media (prefers-reduced-motion: reduce) {
  .wn-backdrop,
  .wn-backdrop.open,
  .wn-modal,
  .wn-backdrop.open .wn-modal {
    transition: opacity 120ms ease, visibility 0s;
    transform: none;
  }
  .wn-backdrop.open .wn-body.wn-intro .wn-item,
  .wn-backdrop.open .wn-body.wn-intro .wn-release-head,
  .wn-backdrop.open .wn-body.wn-intro .wn-release-title {
    animation: none;
  }
  .whatsnew-btn:active { transform: none; }
}

/* ---- Tab switching ----
   A crossfade. The modal is intentionally NOT height-animated: it sizes itself
   through flex + max-height. Animating its height meant fighting both of those
   at once, which made the box resize in a stiff, snapping way. Since the box
   only changes size while the content is invisible, the resize isn't something
   you watch happen. */
.wn-body.wn-out .wn-release,
.wn-body.wn-out .wn-sep {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 130ms ease, transform 130ms ease;
}
/* The new content eases in alongside the box's growth (rather than snapping in
   before the box finishes expanding, which made the two look disconnected). */
.wn-body.wn-in .wn-release,
.wn-body.wn-in .wn-sep {
  animation: wn-fade-in 340ms cubic-bezier(0.4, 0.0, 0.2, 1) 60ms backwards;
}
@keyframes wn-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .wn-body { transition: none; }
  .wn-body.wn-out .wn-release,
  .wn-body.wn-out .wn-sep { opacity: 1; transform: none; transition: none; }
  .wn-body.wn-in .wn-release,
  .wn-body.wn-in .wn-sep { animation: none; }
}

/* ---- Login page placement ----
   On login there is no header, so the button floats in the top-right corner.
   It is positioned over the background image, so it needs its own backdrop. */
.whatsnew-btn--login {
  position: fixed;
  top: 22px;
  right: 26px;
  z-index: 50;
  background: rgba(10, 22, 38, 0.55);
  backdrop-filter: blur(6px);
  border-color: rgba(255, 255, 255, 0.16);
  color: rgba(255, 255, 255, 0.82);
}
.whatsnew-btn--login:hover {
  background: rgba(10, 22, 38, 0.75);
  color: #fff;
}
@media (max-width: 620px) {
  .whatsnew-btn--login { top: 14px; right: 14px; }
  .whatsnew-btn--login .whatsnew-label { display: none; }
}
