/* Site-wide aesthetic foundation: one scale for type, radius, shadow and motion.
   Loaded last. Selectors stay low-specificity (:where) so explicit component
   rules keep winning; the gradient header and annotation colours are untouched. */
@font-face {
  font-family: "EssayPilot Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("./fonts/inter/inter-latin.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2010-2027, U+2030-203A, U+20AC, U+2122, U+2190-2193, U+2212, U+2215, U+2713;
}

:root {
  --ds-text-xs: 12px;
  --ds-text-sm: 14px;
  --ds-text-md: 16px;
  --ds-text-lg: 20px;
  --ds-text-xl: 28px;
  --ds-leading-tight: 1.35;
  --ds-leading-ui: 1.5;
  --ds-leading-read: 1.8;
  --ds-radius-xs: 4px;
  --ds-radius-sm: 8px;
  --ds-radius-md: 12px;
  --ds-radius-lg: 16px;
  --ds-radius-pill: 999px;
  --ds-ink-shadow: 34, 52, 78;
  --ds-shadow-1: 0 1px 2px rgba(var(--ds-ink-shadow), .06);
  --ds-shadow-2: 0 1px 2px rgba(var(--ds-ink-shadow), .04), 0 8px 24px rgba(var(--ds-ink-shadow), .075);
  --ds-shadow-3: 0 2px 6px rgba(var(--ds-ink-shadow), .06), 0 16px 40px rgba(var(--ds-ink-shadow), .16);
  --ds-ease: cubic-bezier(.22, .75, .25, 1);
  --ds-dur-fast: 150ms;
  --ds-dur: 220ms;
  --ds-focus: #3f669b;
  --ds-sans: "EssayPilot Inter", Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI",
    "PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --ds-serif: "EssayPilot Noto Serif SC", "Noto Serif SC", "Source Han Serif SC", "Songti SC", Georgia, serif;
}

@media screen {
  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scroll-behavior: smooth;
  }
  body.ep-top-navigation {
    font-family: var(--ds-sans);
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-synthesis: none;
    font-kerning: normal;
  }

  /* Reading rhythm: balanced headings, no orphan characters, looser Chinese leading. */
  body.ep-top-navigation :where(h1, h2, h3, h4) {
    text-wrap: balance;
    line-height: var(--ds-leading-tight);
  }
  body.ep-top-navigation :where(p, li, blockquote, figcaption, dd) {
    text-wrap: pretty;
    overflow-wrap: anywhere;
    hanging-punctuation: first allow-end;
  }
  body.ep-top-navigation :where(.migration-main p, .migration-main li, .migration-main blockquote) {
    line-height: var(--ds-leading-read);
  }
  body.ep-top-navigation :where(.migration-main p + p) {
    margin-top: .85em;
  }

  /* Numbers read as data: aligned columns for scores, counts and timers. */
  body.ep-top-navigation :where(
    [class*="score"], [class*="band"], [class*="count"], [class*="timer"],
    [class*="percent"], [class*="stat"], table, time, output
  ) {
    font-variant-numeric: tabular-nums lining-nums;
  }

  /* One focus ring everywhere; keyboard only, never on mouse clicks. */
  body.ep-top-navigation :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--ds-focus);
    outline-offset: 2px;
    border-radius: var(--ds-radius-xs);
  }
  body.ep-top-navigation :where(a, button, summary, [role="button"]):focus:not(:focus-visible) {
    outline: none;
  }

  /* Quiet, consistent micro-motion; component rules with their own transition win. */
  body.ep-top-navigation :where(a, button, summary, [role="button"], input, select, textarea) {
    transition:
      color var(--ds-dur-fast) var(--ds-ease),
      background-color var(--ds-dur-fast) var(--ds-ease),
      border-color var(--ds-dur-fast) var(--ds-ease),
      box-shadow var(--ds-dur-fast) var(--ds-ease),
      opacity var(--ds-dur-fast) var(--ds-ease);
  }

  ::selection {
    background: rgba(71, 101, 142, .22);
    color: inherit;
  }
  html {
    scrollbar-width: thin;
    scrollbar-color: #b9c4d4 transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: .01ms !important;
  }
}

/* Body-level progress escapes the report's lower stacking context.
   report-scroll.mjs supplies the real document progress, also without timelines. */
.ep-report-reading-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 60;
  pointer-events: none;
  background: linear-gradient(90deg, #6f93c4, #345e92);
  transform-origin: 0 50%;
  transform: scaleX(0);
}
@media (prefers-reduced-motion: no-preference) {
  .migration-report-page [data-report-revealed] {
    /* Time-based, once per card; reverse scrolling cannot rewind it.
       Individual translate leaves existing hover transforms untouched. */
    animation: ep-report-enter 480ms cubic-bezier(.2,.7,.2,1) both;
  }
}
@keyframes ep-report-enter {
  from { opacity: 0; translate: 0 14px; }
  to { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce), print {
  .ep-report-reading-progress { display: none; }
  .migration-report-page [data-report-revealed] { animation: none; }
}

/* Scroll polish, round 2. Everything here is presentation-only and degrades to
   the static layout without animation-timeline / @starting-style support. */

/* Score meters fill once, together with their card's one-time entrance. */
@media (prefers-reduced-motion: no-preference) {
  .migration-report-page [data-report-revealed] .ep-report-criterion__meter {
    animation: ep-meter-fill 720ms .22s cubic-bezier(.2,.7,.2,1) both;
  }
}
@keyframes ep-meter-fill {
  from { clip-path: inset(0 100% 0 0 round 99px); }
  to { clip-path: inset(0 0 0 0 round 99px); }
}
.ep-report-count-final {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Sticky topic headings in the arsenal directory. A flex column (not grid) so the
   heading's containing block is the whole scrolling list, not its own grid row. */
@media screen {
  .migration-arsenal-page .ep-arsenal-directory__items { display: flex; flex-direction: column; }
  .migration-arsenal-page .ep-arsenal-directory__items > * { flex-shrink: 0; }
  .migration-arsenal-page .ep-arsenal-directory__topic {
    position: sticky;
    top: 0;
    z-index: 2;
    padding-block: 6px;
    background: linear-gradient(#e1e9f5 75%, transparent);
  }
}

/* Edge fades on the independently scrolling directory: the top fade appears once
   scrolled, the bottom fade disappears at the end. Inactive when nothing overflows. */
@property --ds-fade-top { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --ds-fade-bottom { syntax: '<length>'; inherits: false; initial-value: 0px; }
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .migration-arsenal-page .ep-arsenal-directory__items {
      animation: ds-fade-top linear both, ds-fade-bottom linear both;
      animation-timeline: scroll(self), scroll(self);
      animation-range: 0 10px, calc(100% - 10px) 100%;
      -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--ds-fade-top), #000 calc(100% - var(--ds-fade-bottom)), transparent);
      mask-image: linear-gradient(to bottom, transparent, #000 var(--ds-fade-top), #000 calc(100% - var(--ds-fade-bottom)), transparent);
    }
    .migration-arsenal-page .ep-arsenal-directory__items:focus-within {
      /* Masking must never fade a keyboard outline or the actively selected row. */
      -webkit-mask-image: none;
      mask-image: none;
    }
  }
}
@keyframes ds-fade-top { from { --ds-fade-top: 0px; } to { --ds-fade-top: 10px; } }
@keyframes ds-fade-bottom { from { --ds-fade-bottom: 10px; } to { --ds-fade-bottom: 0px; } }

/* Phones: the four score cards become a snap-scrolling row; the next card peeks. */
@media screen and (max-width: 520px) {
  .migration-report-page .ep-report-criteria {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 84%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    padding-bottom: .4rem;
    scrollbar-width: thin;
    scroll-padding-inline: 4px;
    padding-inline: 4px;
  }
  .migration-report-page .ep-report-criteria > * { scroll-snap-align: start; }
}

/* "Back to latest" fades in and out instead of popping. */
body .ep-chat-shell .ep-chat-latest[hidden] { pointer-events: none; }
@supports (transition-behavior: allow-discrete) {
  @media (prefers-reduced-motion: no-preference) {
    body .ep-chat-shell .ep-chat-latest {
      opacity: 1;
      translate: 0 0;
      transition: opacity .2s ease, translate .2s ease, display .2s allow-discrete;
    }
    body .ep-chat-shell .ep-chat-latest[hidden] { opacity: 0; translate: 0 8px; }
    @starting-style {
      body .ep-chat-shell .ep-chat-latest { opacity: 0; translate: 0 8px; }
    }
  }
}

@media (prefers-reduced-motion: reduce), print {
  .migration-report-page .ep-report-criterion__meter { animation: none; clip-path: none; }
  body .ep-chat-shell .ep-chat-latest { transition: none; translate: none; }
}
@media print {
  .migration-report-page .ep-report-criteria {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-flow: row;
    grid-auto-columns: auto;
    overflow: visible;
    scroll-snap-type: none;
  }
  .migration-arsenal-page .ep-arsenal-directory__items { animation: none; -webkit-mask-image: none; mask-image: none; }
  body .ep-chat-shell .ep-chat-latest { display: none; }
}
