/* =============================================================================
   Atlassian Spacing Tokens — 8px base unit
   https://atlassian.design/foundations/spacing
   Shared conventions with the Penn MEDIATED /home and /about repos.
   ============================================================================= */
:root {
  --space-025:   2px;
  --space-050:   4px;
  --space-075:   6px;
  --space-100:   8px;
  --space-150:  12px;
  --space-200:  16px;
  --space-250:  20px;
  --space-300:  24px;
  --space-400:  32px;
  --space-500:  40px;
  --space-600:  48px;
  --space-800:  64px;
  --space-1000: 80px;

  /* ── Figma colour tokens ── */
  --c-bg:         #ffffff;
  --c-dark:       #0d0d0c;          /* rgb(13,13,12)   */
  --c-light-bg:   #f8f7f4;          /* rgb(248,247,244)*/
  --c-pale-orange: #fce4dc;         /* rgb(252,228,220) — --c-red tinted ~12% onto white; matches /grants' --c-pale-orange exactly */
  --c-accent:     #5533ee;          /* rgb(85,51,238)  */
  --c-red:        #f03d1f;          /* rgb(240,61,31)  */
  /* Deeper red-orange — the gradient's closing stop, promoted to a token
     of its own. Link text on a white/light ground uses this: --c-red
     only reaches ~3.9:1 against white, this clears 4.5:1. --c-red stays
     the brand accent for fills, borders, icons, tags and labels. */
  --c-red-dark:   #df3611;
  --c-gray:       #888680;          /* rgb(136,134,128)*/
  --c-gray-dark:  #54534f;          /* rgb(84,83,79) — opaque body copy, ~8:1 contrast on white */
  --c-white:      #ffffff;

  /* Brand gradient — reserved, matches /home and /about exactly:
     150deg #5533ee 0% → #df3611 81% */
  --c-gradient: linear-gradient(150deg, #5533ee 0%, var(--c-red-dark) 81%);

  /* ── Figma typography tokens ── */
  /* Two families, no third — and the split is by what the text IS, not by
     heading level. --f-serif: page titles, and titles of works or names of
     people (a post title, a paper title, a person's name), plus pull-quote
     copy. --f-sans: section headings, card and UI labels, running prose,
     metadata, controls and uppercase micro-labels.
     The one that trips people up: a SECTION HEADING IS NOT SERIF. Serif
     marks a thing that has its own name; sans marks the furniture around
     it. See README -> Typography. */
  --f-serif: 'EB Garamond', Georgia, 'Times New Roman', serif;
  --f-sans:  'DM Sans', system-ui, -apple-system, sans-serif;
  /* -- Type scale (sitewide -- see README) --------------------------------
     Fluid: each clamp() interpolates between the mobile floor and the
     desktop ceiling, so tablet needs no separate breakpoint override.
     12px is the hard floor; nothing on the site ships smaller.         */
  --fs-display:     clamp(36px, 22.7px + 3.70vw, 76px);
  --fs-h1:          clamp(36px, 29.3px + 1.85vw, 56px);
  --fs-h2:          clamp(26px, 21.3px + 1.30vw, 40px);
  --fs-h3:          clamp(20px, 18.7px + 0.37vw, 24px);
  --fs-lede:        clamp(18px, 17.3px + 0.19vw, 20px);
  --fs-body:        16px;
  --fs-small:       14px;
  --fs-small-serif: 15px;   /* EB Garamond runs ~1px small beside DM Sans */
  --fs-micro:       12px;   /* uppercase labels, tags, meta -- the floor */

  --lh-display: 1.05;
  --lh-heading: 1.15;
  --lh-lede:    1.26;
  --lh-title:   1.3;
  --lh-body:    1.55;

  /* ── Page layout ── */
  --max-w: 1440px;
  --pad-x: var(--space-1000);   /* 80px side padding — page-level rhythm */
}

/* Side padding scales down on smaller screens — 80px fixed padding eats
   ~43% of a 375px phone width otherwise. Matches /home's breakpoints. */
@media (max-width: 900px) {
  :root { --pad-x: var(--space-400); }  /* 32px */
}
@media (max-width: 480px) {
  :root { --pad-x: var(--space-250); }  /* 20px */
}

/* =============================================================================
   External Link Arrow Badge
   Black circle + white arrow that signals "opens an external site." Matches
   /about's card-arrow exactly — host element needs position: relative. On
   hover, the badge switches to a continuously sliding purple-to-orange
   gradient (the brand gradient's own colors) rather than a flat color swap.
   ============================================================================= */
.card-arrow {
  position: absolute;
  top: var(--space-100);
  right: var(--space-100);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--c-dark);
  color: var(--c-white);
  font-size: var(--fs-micro);
  line-height: 1;
  transition: transform 0.2s ease;
  pointer-events: none;
}
@keyframes card-arrow-slide {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
a:hover .card-arrow {
  transform: scale(1.15) translate(2px, -2px);
  background: linear-gradient(100deg, var(--c-accent), var(--c-red), var(--c-accent));
  background-size: 220% 100%;
  animation: card-arrow-slide 1.2s linear infinite;
}

/* =============================================================================
   Reset
   ============================================================================= */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--f-sans);
  color: var(--c-dark);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }
button { font: inherit; cursor: pointer; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border-width: 0;
}

/* =============================================================================
   Shared inner container
   ============================================================================= */
.intro__inner,
.data-projects__inner {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

/* =============================================================================
   INTRO
   Page title + PennMAP description. Same "chapter" pattern as /about's
   .mission — serif accent-purple title, DM Sans Light 20px body copy —
   just used for the page's own h1 instead of a "Mission Statement" h2.
   ============================================================================= */
.intro {
  background: var(--c-bg);
  padding-top: var(--space-1000);
  padding-bottom: var(--space-600);
}

.intro__title {
  font-family: var(--f-serif);
  font-size: var(--fs-h1);
  font-weight: 600;
  line-height: var(--lh-display);
  color: var(--c-accent);
  margin-bottom: var(--space-250);
}

/* Weight 700: sitewide, 700 is the white-background section-heading
   weight and 600 is reserved for headings on colored blocks. */
.intro__subtitle {
  font-family: var(--f-sans);
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: var(--lh-heading);
  color: var(--c-dark);
  margin-top: var(--space-800);
  margin-bottom: var(--space-300);
}

.intro__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-300);
  max-width: 1205px;   /* matches /about's .mission__body exactly */
}

.intro__body p {
  font-family: var(--f-sans);
  font-size: var(--fs-lede);
  font-weight: 300;
  line-height: var(--lh-lede);
  color: var(--c-dark);
}

/* In-text links (Hyperlinks category 1) on a white/light ground:
   --c-red, no underline, fading to opacity 0.7 on hover — the same
   fade the coloured-ground rule uses. Colour is the affordance here;
   the underline belongs to category 2's independent links. */
.intro__body a {
  color: var(--c-red-dark);
  font-weight: 500;
  transition: opacity 0.15s;
}

.intro__body a:hover { opacity: 0.7; }

/* =============================================================================
   DATA PROJECTS
   3-up grid of external research tools driven by PennMAP data. Native
   image aspect ratios are kept as-is (unlike /home's news-card squares) —
   these are functional dashboard screenshots, and cropping them risks
   cutting off the UI being shown.
   ============================================================================= */
/* Solid brand-purple backdrop, full-bleed edge to edge — matches
   /home's .research-cta treatment (purple 1443×465 section, white
   card with shadow), where the background sits on the outer section
   and only the inner content column is width-constrained. */
.data-projects {
  background: var(--c-accent);
  padding-block: var(--space-1000);
}

.data-projects__box {
  padding: var(--space-600);
}

.data-projects__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-600);
}

@media (max-width: 900px) {
  .data-projects__grid { grid-template-columns: 1fr; }
}

.data-project {
  display: flex;
  flex-direction: column;
  gap: var(--space-200);
  /* Grid items default to min-width:auto, so a large intrinsic image
     width (these dashboard GIFs are 1000-1600px natively) can blow out
     the track even though the img itself is capped to max-width:100%. */
  min-width: 0;
}

.data-project__title {
  font-family: var(--f-sans);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--c-white);
  transition: opacity 0.15s;
}

.data-project:hover .data-project__title { opacity: 0.7; }

.data-project__image {
  position: relative;
  width: 100%;
  overflow: hidden;
  border-radius: var(--space-100);
  box-shadow: 0 24px 64px rgba(0,0,0,0.25);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.data-project:hover .data-project__image {
  transform: translateY(-4px);
  box-shadow: 0 32px 72px rgba(0,0,0,0.32);
}

.data-project__image img { width: 100%; height: auto; display: block; }

/* ── Page end ──────────────────────────────────────────────────────────
   Sitewide (Sept 2026): the last section sits flush on the global footer,
   which opens with its own 132px white signal band. That band is the gap
   before the footer on every page. The old 80px trailing space on top of it
   left 200px+ of white at the end of some pages. */
body { padding-bottom: 0; }

/* ── Trailing-margin guard ─────────────────────────────────────────────────
   These pages are embedded in an iframe that is resized to the height this
   page reports, and that height is measured from document.body.

   A bottom margin on the last element COLLAPSES THROUGH body and out to
   <html>. It never appears in body.scrollHeight, but it does extend
   documentElement.scrollHeight — so the frame gets sized short of the real
   document, the embedded page is left with a few px it can scroll, and it
   swallows the visitor's wheel events: the outer page then only scrolls when
   the cursor is over its scrollbar. It has bitten twice (home, 64px;
   grants-overview, 80px) and it is invisible in the builder.

   display: flow-root makes body a block formatting context, so descendant
   margins can no longer escape it and the measured height is always the whole
   document. Cheap, and it removes a whole class of bug rather than one
   instance. If a page grows here, something was relying on a margin escaping
   — convert that margin to padding rather than removing this.
   ====================================================================== */
body { display: flow-root; }
