/* =============================================================
   home-features.css - styling for the deep feature showcase
   on the landing page (index.html). Each .show block pairs a
   text column with an inline SVG mockup that mirrors the look
   of the corresponding feature inside Sciwand.

   Keep this file scoped to the showcase. Site-wide tokens
   (--ink, --ink-2, --muted, --line, --card, etc.) live in
   site.css. Anything page-global belongs there, not here.
   ============================================================= */

/* --- Section shell -------------------------------------------------- */

.showcase {
  margin: 12px 0 56px;
  /* The showcase opts into the wider 960px wrap inline (see index.html);
     spacing and rhythm are owned by .show. */
}

.showcase-intro {
  text-align: left;
  padding: 4px 0 28px;
}
.showcase-intro h2 {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -1.2px;
  color: var(--ink);
  margin-bottom: 10px;
  line-height: 1.15;
}
.showcase-intro p {
  font-size: 15px;
  color: var(--ink-2);
  max-width: 560px;
  line-height: 1.55;
}

/* --- Individual feature block (text + mock) ------------------------- */

.show {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 56px;
  align-items: center;
  padding: 56px 0;
  border-top: 1px solid var(--line);
}
.show:last-child {
  border-bottom: 1px solid var(--line);
}

/* Alternating layout - every other block flips the mock to the left.
   We use CSS order rather than re-ordering markup so the reading order
   stays logical (kicker → title → lead → bullets → mock) for screen
   readers. */
.show--flip .show-mock { order: 0; }
.show--flip .show-copy { order: 1; }

/* Copy column ------------------------------------------------------- */

.show-kicker {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
}
.show-title {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -1.1px;
  color: var(--ink);
  line-height: 1.18;
  margin-bottom: 14px;
}
.show-lead {
  font-size: 15px;
  color: var(--ink-2);
  line-height: 1.6;
  margin-bottom: 16px;
}
.show-points {
  list-style: none;
  padding: 0;
  margin: 0;
}
.show-points li {
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.6;
  padding-left: 24px;
  position: relative;
  margin-bottom: 6px;
}
/* Tick bullet, drawn as a tiny inline SVG via background-image so we
   keep one rule for every show-points list across the page. */
.show-points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 14px;
  height: 14px;
  background-color: transparent;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8.5l3.2 3.2L13 4.7' fill='none' stroke='%231B8036' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-size: contain;
}

/* Mock column ------------------------------------------------------- */

.show-mock {
  /* Subtle "desktop background" gradient so the inner mockup reads as an
     app window floating over a wallpaper. */
  background:
    radial-gradient(circle at 18% 12%, rgba(99,102,241,0.10), transparent 55%),
    radial-gradient(circle at 82% 90%, rgba(56,189,248,0.10), transparent 55%),
    linear-gradient(140deg, #EAEFFA 0%, #DDE4F2 100%);
  border: 1px solid rgba(15,23,42,0.06);
  border-radius: 14px;
  padding: 28px;
  position: relative;
  overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.6);
}
.show-mock svg {
  width: 100%;
  height: auto;
  display: block;
}

/* .show-mock--bare lets an interactive widget (e.g. the live D3 citation
   graph) own its own framing. We drop the inner padding and let the
   widget render edge-to-edge inside the .show-mock card. */
.show-mock--bare {
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
}

/* --- Shared mockup animation system (.demo-anim) ----------------- */
/* Reusable across any showcase mockup that wants the same demo
   pattern: cursor → click "+ AI column" → modal opens → question
   types itself in → click Add → modal closes → new column header
   appears → 4 rows of data fill in row-by-row.

   The same CSS classes are used in multiple SVGs. Each .demo-anim
   needs:
     .demo-cursor    - cursor arrow group
     .demo-addbtn    - "+ AI column" button (top-right of header)
     .demo-modal     - modal popover group with .demo-type + .demo-caret
     .demo-type      - clip-path wrapper around the question text
     .demo-caret     - blinking caret rect inside the modal
     .demo-newhd     - column header that fades in after modal closes
     .demo-row[data-row="1..4"]  - animated row content groups

   All keyframes share an 8-second cycle. /demo-anim.js adds the
   .is-running class when the mockup scrolls into view; the cycle
   loops infinitely from there.

   Per-cycle timeline (s = wall time within one 8s loop):
     0.0   cursor invisible, ready
     0.3   cursor visible at (40, 320)
     1.0   cursor at "+ AI column" button (440, 14)
     1.1   button click pulse
     1.2   button fades out, modal opens
     1.4   typing of question begins (blinking caret)
     2.8   typing complete
     3.2   cursor at modal "Add" button (448, 200)
     3.3   Add click pulse
     3.5   modal fades out, "MAIN FINDING" / new column header in
     3.7-4.6  rows 1-4 fade in (≈0.3s stagger)
     4.9-6.6  hold complete state
     6.8   rows + new header fade out
     7.2   "+ AI column" button fades back in (reset)
     8.0   loop restart                                              */

/* Cursor "target" positions are per-mockup CSS variables so the
   shared keyframes can glide to the right button in each block.
   Each .demo-anim sets these inline (or via an `is-*` class). */
.demo-anim {
  --aibtn-x: 440px;     /* "+ AI column" button click position */
  --aibtn-y: 14px;
  --addbtn-x: 448px;    /* Modal "Add" button click position */
  --addbtn-y: 200px;
}

/* Default state (no JS, or before scrolling into view): cursor,
   modal, caret, and addbtn are visibility:hidden. Rows + new column
   header stay visible (the static "completed" demo). */
.demo-anim .demo-cursor,
.demo-anim .demo-modal,
.demo-anim .demo-caret,
.demo-anim .demo-addbtn {
  visibility: hidden;
}
.demo-anim.is-running .demo-cursor,
.demo-anim.is-running .demo-modal,
.demo-anim.is-running .demo-caret,
.demo-anim.is-running .demo-addbtn { visibility: visible; }

/* All animations share one 8s cycle so they stay in sync. */
.demo-anim.is-running .demo-cursor { animation: demo-cursor 8s cubic-bezier(.4,0,.2,1) infinite; }
.demo-anim.is-running .demo-addbtn { animation: demo-addbtn 8s linear infinite; }
.demo-anim.is-running .demo-modal  { animation: demo-modal  8s ease-out infinite; transform-origin: 300px 161px; }
.demo-anim.is-running .demo-type   { animation: demo-type   8s linear infinite; clip-path: inset(0 100% 0 0); }
.demo-anim.is-running .demo-caret  {
  animation: demo-caret      8s steps(20, end) infinite,
             demo-caret-move 8s linear infinite;
}
.demo-anim.is-running .demo-newhd  { animation: demo-newhd  8s linear infinite; opacity: 0; }
.demo-anim.is-running .demo-row    { opacity: 0; transform: translateY(6px); }
.demo-anim.is-running .demo-row[data-row="1"] { animation: demo-row-1 8s linear infinite; }
.demo-anim.is-running .demo-row[data-row="2"] { animation: demo-row-2 8s linear infinite; }
.demo-anim.is-running .demo-row[data-row="3"] { animation: demo-row-3 8s linear infinite; }
.demo-anim.is-running .demo-row[data-row="4"] { animation: demo-row-4 8s linear infinite; }

@keyframes demo-cursor {
  0%    { opacity: 0; transform: translate(40px, 320px); }
  4%    { opacity: 1; }
  12%   { transform: translate(var(--aibtn-x), var(--aibtn-y)); }
  14%   { transform: translate(var(--aibtn-x), var(--aibtn-y)) scale(0.85); }
  16%   { transform: translate(var(--aibtn-x), var(--aibtn-y)) scale(1); }
  37%   { transform: translate(var(--addbtn-x), var(--addbtn-y)); }
  40%   { transform: translate(var(--addbtn-x), var(--addbtn-y)) scale(0.85); }
  42%   { transform: translate(var(--addbtn-x), var(--addbtn-y)) scale(1); }
  46%   { opacity: 1; }
  50%   { opacity: 0; transform: translate(var(--addbtn-x), var(--addbtn-y)); }
  95%   { opacity: 0; transform: translate(40px, 320px); }
  100%  { opacity: 0; transform: translate(40px, 320px); }
}
@keyframes demo-addbtn {
  0%, 13%  { opacity: 1; }
  15%      { opacity: 0; }
  88%      { opacity: 0; }
  92%      { opacity: 1; }
  100%     { opacity: 1; }
}
@keyframes demo-modal {
  0%, 14%  { opacity: 0; transform: scale(0.96); }
  17%      { opacity: 1; transform: scale(1); }
  42%      { opacity: 1; transform: scale(1); }
  45%      { opacity: 0; transform: scale(0.96); }
  100%     { opacity: 0; }
}
@keyframes demo-type {
  0%, 18%  { clip-path: inset(0 100% 0 0); }
  35%      { clip-path: inset(0 0 0 0); }
  43%      { clip-path: inset(0 0 0 0); }
  44%      { clip-path: inset(0 100% 0 0); }
  100%     { clip-path: inset(0 100% 0 0); }
}
/* Caret blinks ~5 times during the typing window, then hides. */
@keyframes demo-caret {
  0%, 17%   { opacity: 0; }
  18%, 21%  { opacity: 1; }
  22%, 25%  { opacity: 0; }
  26%, 29%  { opacity: 1; }
  30%, 33%  { opacity: 0; }
  34%, 37%  { opacity: 1; }
  38%, 41%  { opacity: 0; }
  42%, 100% { opacity: 0; }
}
/* Caret tracks the end of the typed text. Each .demo-anim sets
   --caret-end inline (in px) based on the text width of its
   question. */
@keyframes demo-caret-move {
  0%, 17%   { transform: translateX(0); }
  35%       { transform: translateX(var(--caret-end, 160px)); }
  43%       { transform: translateX(var(--caret-end, 160px)); }
  44%, 100% { transform: translateX(0); }
}
@keyframes demo-newhd {
  0%, 43%  { opacity: 0; }
  46%      { opacity: 1; }
  85%      { opacity: 1; }
  90%      { opacity: 0; }
  100%     { opacity: 0; }
}
/* Per-row keyframes only differ in the appearance percentage (~3%
   stagger). Wrapping into a tiny mixin would need SCSS, so listed
   explicitly to keep this stylesheet build-step-free. */
@keyframes demo-row-1 {
  0%, 46%  { opacity: 0; transform: translateY(6px); }
  50%      { opacity: 1; transform: translateY(0); }
  85%      { opacity: 1; }
  90%      { opacity: 0; }
  100%     { opacity: 0; }
}
@keyframes demo-row-2 {
  0%, 49%  { opacity: 0; transform: translateY(6px); }
  53%      { opacity: 1; transform: translateY(0); }
  85%      { opacity: 1; }
  90%      { opacity: 0; }
  100%     { opacity: 0; }
}
@keyframes demo-row-3 {
  0%, 52%  { opacity: 0; transform: translateY(6px); }
  56%      { opacity: 1; transform: translateY(0); }
  85%      { opacity: 1; }
  90%      { opacity: 0; }
  100%     { opacity: 0; }
}
@keyframes demo-row-4 {
  0%, 55%  { opacity: 0; transform: translateY(6px); }
  59%      { opacity: 1; transform: translateY(0); }
  85%      { opacity: 1; }
  90%      { opacity: 0; }
  100%     { opacity: 0; }
}

/* -------- .is-cited variant ---------------------------------------
   For mockups where each row is a "claim" the reader needs to
   process individually (Cited & verifiable, Reference manager) -
   stretches the stagger so each row gets ~1s of dwell instead of
   the tight 0.3s of the default. */
.demo-anim.is-cited .demo-row[data-row="1"] { animation: cited-row-1 8s linear infinite; }
.demo-anim.is-cited .demo-row[data-row="2"] { animation: cited-row-2 8s linear infinite; }
.demo-anim.is-cited .demo-row[data-row="3"] { animation: cited-row-3 8s linear infinite; }
.demo-anim.is-cited .demo-row[data-row="4"] { animation: cited-row-4 8s linear infinite; }

@keyframes cited-row-1 {
  0%, 16% { opacity: 0; transform: translateY(6px); }
  21%     { opacity: 1; transform: translateY(0); }
  85%     { opacity: 1; }
  92%     { opacity: 0; }
}
@keyframes cited-row-2 {
  0%, 28% { opacity: 0; transform: translateY(6px); }
  33%     { opacity: 1; transform: translateY(0); }
  85%     { opacity: 1; }
  92%     { opacity: 0; }
}
@keyframes cited-row-3 {
  0%, 40% { opacity: 0; transform: translateY(6px); }
  45%     { opacity: 1; transform: translateY(0); }
  85%     { opacity: 1; }
  92%     { opacity: 0; }
}
@keyframes cited-row-4 {
  0%, 52% { opacity: 0; transform: translateY(6px); }
  57%     { opacity: 1; transform: translateY(0); }
  85%     { opacity: 1; }
  92%     { opacity: 0; }
}

/* -------- .is-search variant --------------------------------------
   The Search-the-literature mockup has a different cursor flow: it
   clicks two source-database chips before the query types in, and
   the query is meant to PERSIST so the user can read it. */
.demo-anim.is-search .demo-cursor {
  animation: demo-cursor-search 8s cubic-bezier(.4,0,.2,1) infinite;
}
.demo-anim.is-search .demo-type {
  animation: demo-type-search 8s linear infinite;
  clip-path: inset(0 100% 0 0);
}
.demo-anim.is-search .demo-caret {
  animation: demo-caret-search      8s steps(20, end) infinite,
             demo-caret-move-search 8s linear infinite;
}
.demo-anim.is-search .demo-pick-1,
.demo-anim.is-search .demo-pick-2 {
  opacity: 0;
}
.demo-anim.is-search .demo-pick-1 { animation: demo-pick-1 8s linear infinite; }
.demo-anim.is-search .demo-pick-2 { animation: demo-pick-2 8s linear infinite; }

/* Result rows: default keyframes appear at ~50%, which collides with
   the query typing. .is-search uses its own row keyframes that wait
   until the "searching..." beat finishes (>55%). */
.demo-anim.is-search .demo-row[data-row="1"] { animation: search-row-1 8s linear infinite; }
.demo-anim.is-search .demo-row[data-row="2"] { animation: search-row-2 8s linear infinite; }
.demo-anim.is-search .demo-row[data-row="3"] { animation: search-row-3 8s linear infinite; }

/* Status line: 4 stacked text elements at the same x/y; only one
   visible per beat so the sequence reads: nothing -> 1 source ->
   2 sources + searching -> final result counts. */
.demo-anim.is-search .db-status-1,
.demo-anim.is-search .db-status-2,
.demo-anim.is-search .db-status-3,
.demo-anim.is-search .db-status-4 { opacity: 0; }
.demo-anim.is-search:not(.is-running) .db-status-4 { opacity: 1; }
.demo-anim.is-search.is-running .db-status-1 { animation: db-status-1 8s linear infinite; }
.demo-anim.is-search.is-running .db-status-2 { animation: db-status-2 8s linear infinite; }
.demo-anim.is-search.is-running .db-status-3 { animation: db-status-3 8s linear infinite; }
.demo-anim.is-search.is-running .db-status-4 { animation: db-status-4 8s linear infinite; }

@keyframes db-status-1 {
  0%, 13%   { opacity: 1; }
  15%, 92%  { opacity: 0; }
  95%, 100% { opacity: 1; }
}
@keyframes db-status-2 {
  0%, 13%   { opacity: 0; }
  15%, 22%  { opacity: 1; }
  24%, 100% { opacity: 0; }
}
@keyframes db-status-3 {
  0%, 23%   { opacity: 0; }
  25%, 53%  { opacity: 1; }
  55%, 100% { opacity: 0; }
}
@keyframes db-status-4 {
  0%, 54%   { opacity: 0; }
  56%, 90%  { opacity: 1; }
  93%, 100% { opacity: 0; }
}

@keyframes search-row-1 {
  0%, 54%   { opacity: 0; transform: translateY(6px); }
  58%       { opacity: 1; transform: translateY(0); }
  88%       { opacity: 1; }
  92%, 100% { opacity: 0; transform: translateY(6px); }
}
@keyframes search-row-2 {
  0%, 60%   { opacity: 0; transform: translateY(6px); }
  64%       { opacity: 1; transform: translateY(0); }
  88%       { opacity: 1; }
  92%, 100% { opacity: 0; transform: translateY(6px); }
}
@keyframes search-row-3 {
  0%, 66%   { opacity: 0; transform: translateY(6px); }
  70%       { opacity: 1; transform: translateY(0); }
  88%       { opacity: 1; }
  92%, 100% { opacity: 0; transform: translateY(6px); }
}

@keyframes demo-cursor-search {
  0%    { opacity: 0; transform: translate(40px, 320px); }
  4%    { opacity: 1; }
  10%   { transform: translate(var(--chip1-x), var(--chip1-y)); }
  12%   { transform: translate(var(--chip1-x), var(--chip1-y)) scale(0.85); }
  14%   { transform: translate(var(--chip1-x), var(--chip1-y)) scale(1); }
  20%   { transform: translate(var(--chip2-x), var(--chip2-y)); }
  22%   { transform: translate(var(--chip2-x), var(--chip2-y)) scale(0.85); }
  24%   { transform: translate(var(--chip2-x), var(--chip2-y)) scale(1); }
  30%   { transform: translate(40px, 40px); opacity: 1; }
  36%   { opacity: 0; transform: translate(40px, 40px); }
  100%  { opacity: 0; }
}
/* Typing starts only after the cursor has clicked both chips, and
   then PERSISTS to the end of the loop (no clear at 44%). */
/* Query stays visible from ~40% through ~88% so the user has time
   to read it; then it clears with the rest of the elements so the
   loop resets cleanly. */
@keyframes demo-type-search {
  0%, 26%   { clip-path: inset(0 100% 0 0); }
  40%       { clip-path: inset(0 0 0 0); }
  88%       { clip-path: inset(0 0 0 0); }
  92%, 100% { clip-path: inset(0 100% 0 0); }
}
@keyframes demo-caret-search {
  0%, 25%   { opacity: 0; }
  26%, 29%  { opacity: 1; }
  30%, 33%  { opacity: 0; }
  34%, 37%  { opacity: 1; }
  38%, 100% { opacity: 0; }
}
@keyframes demo-caret-move-search {
  0%, 25%   { transform: translateX(0); }
  40%       { transform: translateX(var(--caret-end, 270px)); }
  100%      { transform: translateX(var(--caret-end, 270px)); }
}
/* Chip "selected" overlay appears just after its click pulse and
   stays on until the loop resets. */
@keyframes demo-pick-1 {
  0%, 12%   { opacity: 0; }
  14%       { opacity: 1; }
  88%       { opacity: 1; }
  92%       { opacity: 0; }
}
@keyframes demo-pick-2 {
  0%, 22%   { opacity: 0; }
  24%       { opacity: 1; }
  88%       { opacity: 1; }
  92%       { opacity: 0; }
}
/* -------- .is-sync variant ---------------------------------------
   For the Reference manager mockup. Source cards + arrows stay
   visible the whole loop. On each cycle the cursor clicks a "Sync"
   button on the Sciwand hub; small document particles then flow
   along each existing arrow path from source card to hub. The
   button label morphs through three states:
     Sync now → Syncing 247 items… → 247 imported
   Particles use CSS offset-path so they follow the curved arrow
   exactly. Each particle has its own animation-delay inline so the
   wave staggers. */
.demo-anim.is-sync .demo-row { opacity: 1; transform: none; }
.demo-anim.is-sync.is-running .demo-row {
  opacity: 1; transform: none; animation: none;
}
.demo-anim.is-sync.is-running .demo-cursor {
  animation: demo-cursor-sync 8s cubic-bezier(.4,0,.2,1) infinite;
}

/* Sync-button state labels - only one visible at a time. */
.demo-anim.is-sync .rm-syncstate-1,
.demo-anim.is-sync .rm-syncstate-2,
.demo-anim.is-sync .rm-syncstate-3 { opacity: 0; }
.demo-anim.is-sync.is-running .rm-syncstate-1 { animation: rm-syncstate-1 8s linear infinite; }
.demo-anim.is-sync.is-running .rm-syncstate-2 { animation: rm-syncstate-2 8s linear infinite; }
.demo-anim.is-sync.is-running .rm-syncstate-3 { animation: rm-syncstate-3 8s linear infinite; }

/* Document particles flying along each source-to-hub arrow. */
.demo-anim.is-sync .rm-flow {
  opacity: 0;
  offset-distance: 0%;
  offset-rotate: 0deg;
}
.demo-anim.is-sync.is-running .rm-flow {
  animation: rm-flow-fly 8s linear infinite;
}
.demo-anim.is-sync .rm-flow-z { offset-path: path('M 204 58  C 280 58,  340 141, 392 142'); }
.demo-anim.is-sync .rm-flow-e { offset-path: path('M 204 106 C 280 106, 340 143, 392 144'); }
.demo-anim.is-sync .rm-flow-m { offset-path: path('M 204 154 C 280 154, 340 145, 392 146'); }
.demo-anim.is-sync .rm-flow-b { offset-path: path('M 204 202 C 280 202, 340 147, 392 148'); }

@keyframes demo-cursor-sync {
  0%    { opacity: 0; transform: translate(40px, 280px); }
  4%    { opacity: 1; }
  10%   { transform: translate(470px, 162px); }
  12%   { transform: translate(470px, 162px) scale(0.85); }
  14%   { transform: translate(470px, 162px) scale(1); }
  24%   { transform: translate(40px, 280px); opacity: 1; }
  30%   { opacity: 0; }
  100%  { opacity: 0; transform: translate(40px, 280px); }
}
@keyframes rm-syncstate-1 {
  0%, 10%   { opacity: 1; }
  13%, 92%  { opacity: 0; }
  95%, 100% { opacity: 1; }
}
@keyframes rm-syncstate-2 {
  0%, 12%   { opacity: 0; }
  15%, 64%  { opacity: 1; }
  67%, 100% { opacity: 0; }
}
@keyframes rm-syncstate-3 {
  0%, 66%   { opacity: 0; }
  69%, 92%  { opacity: 1; }
  95%, 100% { opacity: 0; }
}
@keyframes rm-flow-fly {
  0%   { offset-distance: 0%;   opacity: 0; }
  3%   { offset-distance: 0%;   opacity: 1; }
  18%  { offset-distance: 100%; opacity: 1; }
  20%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* -------- .is-citelink variant -----------------------------------
   For the Cited & verifiable mockup. All three answer claims are
   visible from the start (no row stagger). The cursor visits each
   citation badge [1], [2], [3] in turn; on each click a floating
   PDF window pops up showing the highlighted sentence on the
   referenced page. Only one popup is visible at a time. */
.demo-anim.is-citelink .demo-row { opacity: 1; transform: none; }
.demo-anim.is-citelink.is-running .demo-row {
  opacity: 1; transform: none; animation: none;
}
.demo-anim.is-citelink.is-running .demo-cursor {
  animation: citelink-cursor 8s cubic-bezier(.4,0,.2,1) infinite;
}

/* Floating PDF popups - scale-pulse entrance from the popup centre. */
.demo-anim.is-citelink .ct-pop {
  opacity: 0;
  transform-origin: 442px 188px;
  transform: scale(0.94) translateY(8px);
}
.demo-anim.is-citelink.is-running .ct-pop-1 { animation: citelink-pop-1 8s ease-out infinite; }
.demo-anim.is-citelink.is-running .ct-pop-2 { animation: citelink-pop-2 8s ease-out infinite; }
.demo-anim.is-citelink.is-running .ct-pop-3 { animation: citelink-pop-3 8s ease-out infinite; }

/* Quick fill flash on the badge as the cursor "presses" it. */
.demo-anim.is-citelink.is-running .ct-cite-1 { animation: citelink-cite-1 8s ease-out infinite; }
.demo-anim.is-citelink.is-running .ct-cite-2 { animation: citelink-cite-2 8s ease-out infinite; }
.demo-anim.is-citelink.is-running .ct-cite-3 { animation: citelink-cite-3 8s ease-out infinite; }

@keyframes citelink-cursor {
  0%    { opacity: 0; transform: translate(40px, 340px); }
  3%    { opacity: 1; }
  10%   { transform: translate(148px, 110px); }
  12%   { transform: translate(148px, 110px) scale(0.85); }
  14%   { transform: translate(148px, 110px) scale(1); }
  35%   { transform: translate(148px, 110px); }
  39%   { transform: translate(259px, 198px); }
  41%   { transform: translate(259px, 198px) scale(0.85); }
  43%   { transform: translate(259px, 198px) scale(1); }
  60%   { transform: translate(259px, 198px); }
  64%   { transform: translate(219px, 292px); }
  66%   { transform: translate(219px, 292px) scale(0.85); }
  68%   { transform: translate(219px, 292px) scale(1); }
  85%   { transform: translate(219px, 292px); opacity: 1; }
  92%   { opacity: 0; }
  100%  { opacity: 0; }
}
@keyframes citelink-pop-1 {
  0%, 13%   { opacity: 0; transform: scale(0.94) translateY(8px); }
  16%, 37%  { opacity: 1; transform: scale(1) translateY(0); }
  40%, 100% { opacity: 0; transform: scale(0.94) translateY(8px); }
}
@keyframes citelink-pop-2 {
  0%, 41%   { opacity: 0; transform: scale(0.94) translateY(8px); }
  44%, 62%  { opacity: 1; transform: scale(1) translateY(0); }
  65%, 100% { opacity: 0; transform: scale(0.94) translateY(8px); }
}
@keyframes citelink-pop-3 {
  0%, 66%   { opacity: 0; transform: scale(0.94) translateY(8px); }
  69%, 90%  { opacity: 1; transform: scale(1) translateY(0); }
  93%, 100% { opacity: 0; transform: scale(0.94) translateY(8px); }
}
@keyframes citelink-cite-1 {
  0%, 11%   { fill: #EEF6F0; }
  14%, 18%  { fill: #A6CBA9; }
  21%, 100% { fill: #EEF6F0; }
}
@keyframes citelink-cite-2 {
  0%, 40%   { fill: #EEF6F0; }
  43%, 47%  { fill: #A6CBA9; }
  50%, 100% { fill: #EEF6F0; }
}
@keyframes citelink-cite-3 {
  0%, 65%   { fill: #EEF6F0; }
  68%, 72%  { fill: #A6CBA9; }
  75%, 100% { fill: #EEF6F0; }
}

/* Reduced-motion users get the final state with no animation. */
@media (prefers-reduced-motion: reduce) {
  .demo-anim .demo-cursor, .demo-anim .demo-modal, .demo-anim .demo-caret,
  .demo-anim.is-running .demo-cursor, .demo-anim.is-running .demo-modal,
  .demo-anim.is-running .demo-caret, .demo-anim.is-running .demo-addbtn,
  .demo-anim.is-sync .rm-flow,
  .demo-anim.is-citelink .ct-pop {
    display: none !important;
    animation: none !important;
  }
  /* Show only the idle "Sync now" label so the still frame reads well. */
  .demo-anim.is-sync .rm-syncstate-1 { opacity: 1 !important; }
  .demo-anim.is-sync .rm-syncstate-2,
  .demo-anim.is-sync .rm-syncstate-3 { opacity: 0 !important; }
  .demo-anim.is-running .demo-newhd,
  .demo-anim.is-running .demo-row {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
}

/* --- Connected-database pill strip ------------------------------- */
/* Sits below the "Search the literature" article so the 10 source
   chips don't have to live inside the mockup. Brand colours kept
   for the database icons since brand-recognition matters here. */
.db-strip {
  padding: 44px 0 48px;
}
.db-strip-label {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
  text-align: center;
}
.db-strip-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.db-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 600 12.5px Inter, sans-serif;
  color: var(--ink);
  white-space: nowrap;
}
.db-pill img {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: #f3f4f6;
  padding: 2px;
  box-sizing: border-box;
  object-fit: contain;
}

/* --- AI column types: 3-card explainer ---------------------------- */
/* Sits above the per-feature blocks as a visual TOC of the three
   AI column kinds (free-text, yes/no, score). */
.types-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  padding: 8px 0 32px;
}
.types-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 24px 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.types-card .types-icon {
  width: 100%;
  height: 86px;
  border-radius: 8px;
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* Mono+accent: free-text card goes neutral (no semantic meaning).
   Yes/No keeps its green tint (matches the YES badge inside).
   Score card keeps its warm gradient since the icon shows a
   red/orange/green scale. */
.types-card.is-free .types-icon  { background: linear-gradient(135deg, #f6f6f6 0%, #ececec 100%); }
.types-card.is-yesno .types-icon { background: linear-gradient(135deg, #F5FAF6 0%, #E8F2EB 100%); }
.types-card.is-score .types-icon { background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%); }
.types-kicker {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
}
.types-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.4px;
}
.types-lead {
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.55;
  margin: 0;
}
.types-eg {
  margin-top: 6px;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.5;
  font-style: italic;
}

/* --- Full-width feature block (no copy/mock grid) ----------------- */
/* Used by the D3 citation-graph block so the graph spans the entire
   showcase column. Text stacks above the graph instead of beside it. */
.show--full {
  display: block;
  padding: 56px 0;
  border-top: 1px solid var(--line);
}
.show--full:last-child { border-bottom: 1px solid var(--line); }
.show--full .show-copy {
  max-width: 720px;
  margin: 0 0 28px;
}
.show--full .show-mock { padding: 0; }

/* Section divider between the showcase and the download block --- */
.showcase-foot {
  height: 0;
  margin-top: 0;
}

/* --- Three pillars (Discover / Analyse / Write) ------------------ */
/* Sits between the hero video and the showcase. Concise one-card
   summary per main capability so a first-time reader gets the
   scope before deciding to dive into the deep showcase below. */
.pillars {
  padding: 32px 0 12px;
}
.pillars-head { margin-bottom: 22px; }
.pillars-title {
  font: 800 26px Inter, sans-serif;
  letter-spacing: -1px;
  color: #000;
  line-height: 1.18;
  margin: 0 0 8px;
}
.pillars-lead {
  font-size: 14.5px;
  color: var(--ink-2);
  line-height: 1.55;
  margin: 0;
  max-width: 640px;
}
.pillars-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
.pillar {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 22px 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: var(--ink);
  transition:
    background 0.3s ease,
    color 0.3s ease,
    border-color 0.25s ease,
    box-shadow 0.3s ease;
}
.pillar:hover {
  background: #0a0a0a;
  color: #fff;
  border-color: #0a0a0a;
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.22);
}
.pillar:hover .pillar-icon {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.22);
  color: #fff;
}
.pillar:hover .pillar-kicker { color: rgba(255, 255, 255, 0.65); }
.pillar:hover .pillar-title  { color: #fff; }
.pillar:hover .pillar-body   { color: rgba(255, 255, 255, 0.78); }

.pillar-icon {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: #f3f4f6;
  border: 1px solid #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 6px;
  color: var(--ink);
  transition: background 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}
.pillar-kicker {
  font: 700 11px Inter, sans-serif;
  color: var(--muted);
  letter-spacing: 1.4px;
  text-transform: uppercase;
}
.pillar-title {
  font: 700 18px Inter, sans-serif;
  letter-spacing: -0.4px;
  color: var(--ink);
  margin: 0;
  line-height: 1.25;
}
.pillar-body {
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.55;
  margin: 0;
}

@media (max-width: 760px) {
  .pillars { padding: 24px 0 8px; }
  .pillars-title { font-size: 22px; letter-spacing: -0.8px; }
  .pillars-grid { grid-template-columns: 1fr; gap: 12px; }
  .pillar { padding: 18px 18px 20px; }
}

/* --- Writer-block differentiator table ("vs Jenni.ai & friends") ---
   Lives full-width directly under the Markdown writer article so the
   page rhythm stays alternating-mock/copy without crowding the copy
   column. Reuses the existing .compare-* table styles; the only
   override is .compare-3col, which swaps the grid from 4 columns to
   3 (aspect / them / us). */
.writer-compare {
  margin: 18px 0 8px;
  padding: 22px 24px 20px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
}
.writer-compare-head {
  font: 700 11px Inter, sans-serif;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.writer-compare-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #111;
  color: #fff;
  font: 800 10px Inter, sans-serif;
  letter-spacing: 0.6px;
  padding: 3px 7px;
  border-radius: 6px;
}
/* 3-column variant of the shared .compare-table grid. */
.compare-table.compare-3col {
  grid-template-columns: 0.8fr 1.2fr 1.2fr;
}

@media (max-width: 760px) {
  .writer-compare { padding: 18px 16px 14px; }
  .compare-table.compare-3col { grid-template-columns: 1fr; }
}


/* --- DB strip headline stats ------------------------------------- */
/* Sits between the strip label and the pill row, so the reader gets
   the scale of what Sciwand can reach before scanning the source
   list. Two-row layout on phones. */
.db-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
  padding: 6px 0 22px;
  text-align: center;
}
.db-stat-num {
  font: 800 22px Inter, sans-serif;
  letter-spacing: -0.8px;
  color: var(--ink);
  line-height: 1;
}
.db-stat-lbl {
  font: 500 11px Inter, sans-serif;
  color: var(--muted);
  margin-top: 6px;
  letter-spacing: 0.2px;
}
.db-pill-n {
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 999px;
  background: #EEF6F0;
  color: #134F22;
  font: 700 10.5px Inter, sans-serif;
  letter-spacing: 0.2px;
}
.db-strip-foot {
  font: italic 500 11px Inter, sans-serif;
  color: var(--muted);
  text-align: center;
  margin: 18px 0 0;
  line-height: 1.5;
}

/* --- Comparison table (Sciwand vs Research Rabbit / Connected Papers) ---
   Lives directly under the live citation graph so the reader can
   instantly contrast the demo they just played with the closest
   web alternatives. Sciwand column gets a faint green tint to draw
   the eye without shouting. */
.compare-wrap {
  margin: 36px 0 8px;
  padding: 28px 26px 22px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
}
.compare-title {
  font: 700 17px Inter, sans-serif;
  color: var(--ink);
  letter-spacing: -0.4px;
  margin-bottom: 16px;
}
.compare-table {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  border-top: 1px solid var(--line);
}
.compare-row {
  display: contents;
}
.compare-cell {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  font: 500 13px Inter, sans-serif;
  color: var(--ink-2);
  line-height: 1.45;
  display: flex;
  align-items: center;
  gap: 8px;
}
.compare-feat { font-weight: 600; color: var(--ink); }
.compare-row.compare-head .compare-cell {
  font: 700 12px Inter, sans-serif;
  color: var(--ink);
  letter-spacing: -0.1px;
  background: #fafafa;
}
.compare-cell img {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  object-fit: contain;
  background: #f3f4f6;
  padding: 2px;
  box-sizing: border-box;
  flex: 0 0 18px;
}
.compare-us { background: linear-gradient(180deg, #F5FAF6 0%, #EEF6F0 100%); }
.compare-row .compare-us:not(.compare-head) { background: #F5FAF6; }
.compare-yes,
.compare-no,
.compare-neutral {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: 12.5px;
}
.compare-yes  { color: #134F22; }
.compare-no   { color: #b91c1c; }
.compare-neutral { color: var(--ink-2); }
.compare-yes::before {
  content: '';
  display: inline-block;
  width: 14px; height: 14px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8.5l3.2 3.2L13 4.7' fill='none' stroke='%23134F22' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-size: contain;
  flex: 0 0 14px;
}
.compare-no::before {
  content: '';
  display: inline-block;
  width: 12px; height: 12px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4 4l8 8M12 4l-8 8' stroke='%23b91c1c' stroke-width='2.2' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat;
  background-size: contain;
  flex: 0 0 12px;
}
.compare-foot {
  font: italic 500 11px Inter, sans-serif;
  color: var(--muted);
  margin: 16px 0 0;
}

@media (max-width: 760px) {
  .db-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
  .compare-wrap { padding: 22px 16px 16px; margin: 28px 0 8px; }
  .compare-title { font-size: 15px; }
  .compare-table {
    grid-template-columns: 1fr;
    border-top: none;
  }
  .compare-row { display: block; padding: 14px 0; border-bottom: 1px solid var(--line); }
  .compare-row.compare-head { display: none; }
  .compare-cell {
    border-bottom: none;
    padding: 6px 0;
    background: transparent !important;
  }
  .compare-feat { padding-bottom: 8px; }
  .compare-cell::before {
    content: attr(data-col);
    /* Optional: in a future pass we can add data-col attributes per
       cell for inline labels on mobile. For now the feature row label
       is enough context. */
  }
  .compare-cell.compare-us { background: linear-gradient(180deg, #F5FAF6 0%, #EEF6F0 100%) !important; padding: 8px 10px; border-radius: 8px; }
}

/* --- Languages strip --------------------------------------------- */
/* Sits below the DB strip, full-width inside the same .wrap. Static
   chip cloud + a "live" demo block that swaps script + sample
   question on hover or auto-rotation. */
.lang-strip {
  padding: 56px 0 60px;
  border-top: 1px solid var(--line);
  margin-top: 24px;
}
.lang-strip-label {
  font: 700 11px Inter, sans-serif;
  color: var(--muted);
  letter-spacing: 1.6px;
  text-transform: uppercase;
  margin-bottom: 14px;
}
.lang-strip-title {
  font: 700 26px Inter, sans-serif;
  letter-spacing: -1px;
  color: var(--ink);
  line-height: 1.2;
  max-width: 720px;
  margin: 0 0 14px;
}
.lang-strip-lead {
  font-size: 14.5px;
  color: var(--ink-2);
  line-height: 1.6;
  max-width: 720px;
  margin: 0 0 22px;
}
.lang-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 26px;
}
.lang-chip {
  appearance: none;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 14px;
  font: 600 12.5px Inter, sans-serif;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.lang-chip:hover,
.lang-chip:focus-visible {
  background: #111;
  color: #fff;
  border-color: #111;
  transform: translateY(-1px);
  outline: none;
}
.lang-chip.is-active {
  background: #1B8036;
  border-color: #1B8036;
  color: #fff;
}
.lang-demo {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 22px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 22px 26px;
}
.lang-demo-script {
  font: 700 38px "Inter", "Noto Sans", sans-serif;
  color: var(--ink);
  letter-spacing: -0.4px;
  min-width: 96px;
  text-align: center;
  padding: 10px 18px;
  background: linear-gradient(180deg, #F5FAF6 0%, #EEF6F0 100%);
  border-radius: 10px;
  border: 1px solid #A6CBA9;
  line-height: 1.1;
}
.lang-demo-text { min-width: 0; }
.lang-demo-q {
  font: 600 17px Inter, sans-serif;
  color: var(--ink);
  letter-spacing: -0.3px;
  margin-bottom: 6px;
  line-height: 1.35;
}
.lang-demo-meta {
  font: 500 12px Inter, sans-serif;
  color: var(--muted);
}

@media (max-width: 760px) {
  .lang-strip { padding: 40px 0 44px; }
  .lang-strip-title { font-size: 22px; letter-spacing: -0.8px; }
  .lang-demo { grid-template-columns: 1fr; padding: 18px; gap: 14px; }
  .lang-demo-script { font-size: 30px; min-width: 0; }
  .lang-demo-q { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .lang-chip { transition: none; }
}

/* --- Mobile -------------------------------------------------------- */

@media (max-width: 760px) {
  .showcase-intro h2 { font-size: 24px; letter-spacing: -1px; }
  .show {
    grid-template-columns: 1fr;
    gap: 28px;
    padding: 40px 0;
  }
  /* On mobile, always show the mock first then text. Visual hook
     reads before the copy. */
  .show .show-mock { order: 0; }
  .show .show-copy { order: 1; }
  .show-title { font-size: 22px; letter-spacing: -0.8px; }
  .show-mock { padding: 16px; }

  .types-grid {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .types-card { padding: 20px 18px; }
  .types-card .types-icon { height: 72px; }

  .show--full { padding: 40px 0; }
}

/* --- Comparison tables: collapsible <details> + mobile column labels ---- */
.compare-toggle > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  user-select: none;
}
.compare-toggle > summary::-webkit-details-marker { display: none; }
.compare-toggle > summary::after {
  content: '▾';
  margin-left: auto;
  font-size: 12px;
  color: var(--muted, #6b7280);
  transition: transform 0.15s ease;
}
.compare-toggle[open] > summary::after { transform: rotate(180deg); }
.compare-toggle > summary:hover { color: var(--ink, #111); }

/* Mobile: each value cell carries its column label via data-col so the
   reader knows what each Yes/No refers to without the hidden header row. */
@media (max-width: 720px) {
  .compare-cell[data-col]::before {
    content: attr(data-col);
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--muted, #6b7280);
    margin-bottom: 2px;
  }
}

/* --- Hero secondary CTA (Read the docs) -------------------------------- */
.hero-cta-btn--secondary {
  background: transparent;
  color: var(--ink, #111);
  border: 1px solid var(--line, #e5e7eb);
}
.hero-cta-btn--secondary:hover {
  background: var(--card, #fafafa);
  border-color: var(--ink, #111);
  color: var(--ink, #111);
}
