/* ═══════════════════════════════════════════════════════════════
   Grants (grants.html)
   Self-contained on purpose. grants.html loads css/fonts.css and
   this file, nothing else, so every token and every shared part
   (nav, buttons, footer) is mirrored here the way css/store.css
   mirrors them. If the palette in css/style.css changes, update
   this file, css/store.css and css/terms.css together.

   Art direction is the store at lower volume. This is a reference
   page people scan for money, not a page that sells: the cream
   canvas and the paper-and-shadow cards stay, the marquee and the
   per-card blob do not. What earns colour here is status. The
   deadline chip is the most important object on a card, so it
   carries shape, weight and border style as well as hue, and stays
   readable for someone who does not see the hue at all.
   ═══════════════════════════════════════════════════════════════ */

/* ── Tokens (mirrored from css/style.css) ───────────────────── */
:root {
  color-scheme: light;

  --cream:    #FAF5EC;
  --cream-2:  #F4ECDD;
  --band:     #F6EFE1;
  --paper:    #FFFDF8;

  --ink:      #292437;
  --ink-2:    #4E4760;
  --muted:    #6E6680;

  --green:        #17A15E;
  --green-deep:   #0C7A46;
  --green-bright: #2ED47F;

  --sun:        #FFC933;
  --sun-bright: #FFD23F;
  --amber:      #F0A31A;
  --amber-deep: #8A5A00;

  --violet:        #7C3AED;
  --violet-deep:   #5B21B6;
  --violet-bright: #A78BFA;
  --lilac:         #EDE6FB;

  --line:      rgba(41, 36, 55, .12);
  --line-soft: rgba(41, 36, 55, .07);

  --shadow-sm: 0 2px 8px rgba(70, 56, 110, .05), 0 12px 26px -16px rgba(70, 56, 110, .14);
  --shadow-md: 0 4px 14px rgba(70, 56, 110, .07), 0 24px 48px -22px rgba(70, 56, 110, .20);
  --shadow-lg: 0 6px 18px rgba(70, 56, 110, .08), 0 36px 74px -28px rgba(70, 56, 110, .26);

  --grad-brand: linear-gradient(100deg, var(--green-bright), var(--sun-bright) 48%, var(--violet-bright));
  --grad-text:  linear-gradient(105deg, var(--green-deep), var(--green) 30%, var(--violet) 88%);

  --mono:  'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --sans:  'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --serif: 'Fraunces', Georgia, 'Times New Roman', serif;

  --nav-h: 70px;
  --maxw: 1220px;
  --r: 20px;
  --r-lg: 28px;

  --ease: cubic-bezier(.22, 1, .36, 1);

  --blob-a: 58% 42% 55% 45% / 55% 48% 52% 45%;
  --blob-b: 45% 55% 48% 52% / 48% 55% 45% 55%;
  --blob-c: 52% 48% 42% 58% / 45% 52% 55% 48%;
}

/* Same ramp in a perceptual space where supported. Scoped to @supports
   rather than redeclared, because an unparseable value in a custom
   property fails at use time and would blank the clipped hero title. */
@supports (background: linear-gradient(in oklch, red, blue)) {
  :root {
    --grad-text: linear-gradient(105deg in oklch, var(--green-deep), var(--green) 26%, var(--violet) 92%);
  }
}

/* Dark theme: the cyber-terminal remap, same values as the homepage.
   The purple family maps onto acid lime, which converts every violet
   accent in the light design for free. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --cream:   #060807;
  --cream-2: #0d1310;
  --band:    #0a0f0c;
  --paper:   #0c1310;

  --ink:   #e6f4ec;
  --ink-2: #a9c3b6;
  --muted: #7d9488;

  --green:        #00ff9c;
  --green-deep:   #00ff9c;
  --green-bright: #00ff9c;

  --sun:        #ffd60a;
  --sun-bright: #ffe14d;
  --amber:      #ffb703;
  --amber-deep: #ffd60a;

  --violet:        #b6ff3a;
  --violet-deep:   #d2ff7d;
  --violet-bright: #b6ff3a;
  --lilac:         rgba(182, 255, 58, .13);

  --line:      rgba(0, 255, 156, .2);
  --line-soft: rgba(0, 255, 156, .13);

  --shadow-sm: 0 2px 10px rgba(0, 0, 0, .5),  0 0 0 1px rgba(0, 255, 156, .04);
  --shadow-md: 0 8px 26px rgba(0, 0, 0, .58), 0 0 22px -6px rgba(0, 255, 156, .18);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, .66), 0 0 34px -8px rgba(0, 255, 156, .26);

  --grad-brand: linear-gradient(100deg, var(--green), var(--violet) 50%, var(--sun));
  --grad-text:  linear-gradient(100deg, var(--green), var(--violet) 55%, var(--sun));

  --r: 14px;
  --r-lg: 18px;
}

/* ── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
  background: var(--cream);
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 18px);
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(15px, .55vw + 13.6px, 17px);
  line-height: 1.7;
  overflow-x: hidden;
  accent-color: var(--violet);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* js/grants.js collapses a card with body.hidden, and the panel it hides
   is display:grid below. Every display rule in this file outranks the UA's
   [hidden] {display:none}, so without this the details of every card on
   the page would be stuck open. Same for #progEmpty and #progError. */
[hidden] { display: none !important; }

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
li { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--violet); color: #FBF7EF; }

:focus-visible {
  outline: 3px solid var(--violet);
  outline-offset: 3px;
  border-radius: 6px;
}

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--cream-2); }
::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--green-bright), var(--violet-bright));
  border-radius: 20px;
  border: 3px solid var(--cream-2);
}
::-webkit-scrollbar-thumb:hover { background: var(--violet); }
html { scrollbar-color: var(--violet-bright) var(--cream-2); }

/* The result count and the "closing soon" suffix on an urgent chip are read
   by assistive tech and never seen. js/grants.js also parks its fallback
   copy textarea in this class, so it has to stay off screen WITHOUT
   display:none, which would make that textarea unselectable. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.skip {
  position: fixed; top: -100px; left: 16px; z-index: 999;
  background: var(--violet); color: #fff;
  padding: 10px 18px; border-radius: 999px; font-weight: 700;
  box-shadow: var(--shadow-md);
  transition: top .2s;
}
.skip:focus { top: 14px; }
:root[data-theme="dark"] .skip { color: #04120b; }

/* ── Nav: the same bar as store.html and terms.html ─────────── */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px;
  padding: 0 clamp(16px, 4vw, 42px);
  background: rgba(250, 245, 236, .86);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid var(--line-soft);
  box-shadow: 0 14px 34px -22px rgba(70, 56, 110, .22);
}
:root[data-theme="dark"] .nav {
  background: rgba(6, 8, 7, .82);
  box-shadow: 0 14px 34px -22px rgba(0, 0, 0, .8);
}

.nav__brand { display: flex; align-items: center; gap: 10px; }
.nav__mark { color: var(--violet); display: grid; place-items: center; }
.nav__mark svg { animation: spinSlow 24s linear infinite; }
@keyframes spinSlow { to { transform: rotate(360deg); } }

.nav__name {
  font-family: var(--mono);
  font-weight: 700; font-size: 13.5px; letter-spacing: .2em;
  background: var(--grad-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.nav__end { display: flex; align-items: center; gap: 14px; }
.nav__links { display: flex; align-items: center; gap: 2px; }
.nav__links a {
  position: relative;
  font-family: var(--mono); font-size: 12.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-2);
  padding: 9px 14px; border-radius: 999px;
  transition: color .25s, background .25s;
}
.nav__links a::after {
  content: ''; position: absolute; left: 14px; right: 14px; bottom: 4px;
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--green-bright), var(--violet-bright));
  transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease);
}
.nav__links a:hover { color: var(--violet); background: rgba(124, 58, 237, .07); }
.nav__links a:hover::after { transform: scaleX(1); }
:root[data-theme="dark"] .nav__links a:hover { background: rgba(0, 255, 156, .08); }

/* theme toggle, same control as the homepage */
.themetog {
  position: relative; flex: none;
  width: 58px; height: 30px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--cream-2);
  transition: border-color .25s, box-shadow .25s;
}
.themetog:hover { border-color: var(--violet); box-shadow: 0 0 0 4px rgba(124, 58, 237, .1); }
.themetog__thumb {
  position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--sun), var(--sun-bright));
  color: #6b4d00;
  transition: transform .35s var(--ease), background .35s;
}
.themetog__ico { position: absolute; transition: opacity .25s, transform .35s var(--ease); }
.themetog__ico--moon { opacity: 0; transform: rotate(-50deg) scale(.5); }
:root[data-theme="dark"] .themetog__thumb {
  transform: translateX(28px);
  background: linear-gradient(135deg, var(--green), var(--violet));
  color: #04120b;
  box-shadow: 0 0 14px rgba(0, 255, 156, .5);
}
:root[data-theme="dark"] .themetog__ico--sun  { opacity: 0; transform: rotate(50deg) scale(.5); }
:root[data-theme="dark"] .themetog__ico--moon { opacity: 1; transform: none; }
:root[data-theme="dark"] .themetog:hover { box-shadow: 0 0 0 4px rgba(0, 255, 156, .12); }

/* ── Layout ─────────────────────────────────────────────────── */
.wrap { width: min(var(--maxw), 100% - clamp(32px, 8vw, 96px)); margin-inline: auto; }

/* ── Buttons ────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--sans); font-size: 15px; font-weight: 600;
  letter-spacing: .01em;
  padding: 13px 24px; border-radius: 999px;
  border: 1.5px solid transparent;
  transition: transform .25s var(--ease), box-shadow .25s, background .25s, color .25s, border-color .25s;
  position: relative;
}
.btn svg { flex: none; transition: transform .25s var(--ease); }
.btn:hover { transform: translateY(-2px); }
.btn:hover svg { transform: translateX(3px); }

.btn--solid {
  background: linear-gradient(100deg, var(--green-bright), #19B56A);
  color: #10331F;
  box-shadow: 0 14px 30px -12px rgba(23, 161, 94, .55);
}
.btn--solid:hover { box-shadow: 0 18px 38px -12px rgba(23, 161, 94, .65); }

.btn--ghost {
  border-color: rgba(124, 58, 237, .4);
  color: var(--violet-deep);
  background: rgba(255, 253, 248, .6);
}
.btn--ghost:hover {
  background: var(--lilac);
  border-color: var(--violet);
  box-shadow: 0 12px 28px -14px rgba(124, 58, 237, .4);
}
:root[data-theme="dark"] .btn--solid { color: #04120b; box-shadow: 0 0 26px -6px rgba(0, 255, 156, .6); }
:root[data-theme="dark"] .btn--solid:hover { box-shadow: 0 0 34px -4px rgba(0, 255, 156, .75); }
/* the ghost fill is a hardcoded near-white; on black it reads as a disabled
   grey slab, so it becomes a tinted outline instead */
:root[data-theme="dark"] .btn--ghost {
  background: rgba(182, 255, 58, .06);
  border-color: rgba(182, 255, 58, .45);
  color: var(--violet);
}
:root[data-theme="dark"] .btn--ghost:hover {
  background: rgba(182, 255, 58, .14);
  border-color: var(--violet);
  box-shadow: 0 0 22px -4px rgba(182, 255, 58, .5);
}

/* ── Hero ───────────────────────────────────────────────────── */
/* Two blobs, not the homepage's three. This page is a working tool and the
   controls need to be reachable fast, so the hero is deliberately short. */
.hero {
  position: relative;
  padding: calc(var(--nav-h) + clamp(36px, 5.5vw, 66px)) 0 clamp(30px, 4vw, 46px);
  overflow: clip;
}
.hero::before {
  content: ''; position: absolute; z-index: 0; pointer-events: none;
  top: -190px; right: -150px;
  width: min(620px, 70vw); aspect-ratio: 1;
  background: linear-gradient(135deg, rgba(255, 201, 51, .55), rgba(46, 212, 127, .4) 58%, rgba(167, 139, 250, .28));
  border-radius: var(--blob-a);
  filter: blur(54px);
  animation: blobMorph 24s ease-in-out infinite;
}
.hero__glow {
  position: absolute; z-index: 0; pointer-events: none;
  left: -180px; bottom: -190px;
  width: min(500px, 64vw); aspect-ratio: 1;
  background: linear-gradient(35deg, rgba(167, 139, 250, .44), rgba(46, 212, 127, .2) 70%);
  border-radius: var(--blob-c);
  filter: blur(58px);
  animation: blobMorph 30s ease-in-out infinite reverse;
}
:root[data-theme="dark"] .hero::before {
  background: linear-gradient(135deg, rgba(0, 255, 156, .3), rgba(182, 255, 58, .2) 58%, rgba(255, 214, 10, .14));
}
:root[data-theme="dark"] .hero__glow {
  background: linear-gradient(35deg, rgba(0, 255, 156, .26), rgba(255, 214, 10, .12) 70%);
}

@keyframes blobMorph {
  0%, 100% { border-radius: 58% 42% 55% 45% / 55% 48% 52% 45%; transform: rotate(0deg); }
  33%      { border-radius: 45% 55% 48% 52% / 48% 55% 45% 55%; transform: rotate(4deg); }
  66%      { border-radius: 52% 48% 42% 58% / 45% 52% 55% 48%; transform: rotate(-3deg); }
}

.hero__inner { position: relative; z-index: 1; }

.hero__eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--green-deep);
  background: var(--paper);
  border: 1px solid rgba(23, 161, 94, .28); border-radius: 999px;
  padding: 8px 18px;
  box-shadow: var(--shadow-sm);
  margin-bottom: 22px;
  animation: fadeUp .8s .1s both var(--ease);
}
.hero__eyebrow .dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--green-bright);
  box-shadow: 0 0 0 3px rgba(46, 212, 127, .25);
  animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: .45; transform: scale(.8); } }
:root[data-theme="dark"] .hero__eyebrow {
  background: rgba(0, 255, 156, .05);
  border-color: rgba(0, 255, 156, .3);
}
:root[data-theme="dark"] .hero__eyebrow .dot { box-shadow: 0 0 10px var(--green); }

.hero__title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(38px, 7vw, 74px);
  line-height: 1.04;
  letter-spacing: -.015em;
  max-width: 16ch;
  text-wrap: balance;
  margin-bottom: 18px;
  animation: fadeUp .9s .2s both var(--ease);
}
.hero__title em {
  font-style: italic;
  background: var(--grad-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.hero__blurb {
  max-width: 58ch; color: var(--ink-2);
  font-size: clamp(15px, 1.15vw, 18px);
  animation: fadeUp .9s .32s both var(--ease);
}

/* The honesty line. It is the page's whole promise, so it gets the craft
   typeface and a rule beside it rather than being buried in the blurb. */
.hero__fresh {
  margin-top: 16px;
  max-width: 62ch;
  padding-left: 14px;
  border-left: 3px solid var(--violet-bright);
  font-family: var(--mono); font-size: 12px; line-height: 1.75;
  letter-spacing: .01em;
  color: var(--muted);
  animation: fadeUp .9s .44s both var(--ease);
}
:root[data-theme="dark"] .hero__fresh { border-left-color: var(--violet); }

@keyframes fadeUp { from { opacity: 0; transform: translateY(26px); } }

/* ── Controls ───────────────────────────────────────────────── */
/* Transparent at rest so the hero blobs run under it; the media query near
   the bottom of this block gives it a backdrop only when it is sticky. */
.controls {
  position: relative; z-index: 40;
  padding: clamp(8px, 1.6vw, 16px) 0 clamp(14px, 2vw, 22px);
}

.ctl {
  display: grid;
  gap: clamp(14px, 1.8vw, 20px);
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  padding: clamp(16px, 2.2vw, 24px);
  box-shadow: var(--shadow-sm);
}

.ctl__row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; }

.ctl__row--search { gap: 10px; }

/* The magnifier is a data URI rather than an <img>: the CSP is img-src
   'self' and this keeps the whole control in one file. Two copies, because
   the stroke has to change with the theme. */
.ctl__search {
  flex: 1 1 240px;
  min-width: 0;
  min-height: 48px;
  padding: 12px 16px 12px 46px;
  font-family: var(--sans); font-size: 15.5px; color: var(--ink);
  background-color: var(--cream);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236E6680' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.7-3.7'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 16px center;
  background-size: 19px 19px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  /* Safari otherwise paints its own inset search field over all of this. */
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .25s, box-shadow .25s, background-color .25s;
}
.ctl__search::placeholder { color: var(--muted); opacity: 1; }
.ctl__search:hover { border-color: rgba(124, 58, 237, .4); }
.ctl__search:focus-visible {
  outline: 3px solid var(--violet);
  outline-offset: 3px;
  border-color: var(--violet);
  background-color: var(--paper);
  border-radius: 999px;
}
:root[data-theme="dark"] .ctl__search {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237d9488' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.7-3.7'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] .ctl__search:hover { border-color: rgba(0, 255, 156, .45); }

.ctl__clear {
  flex: none;
  min-height: 44px;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1.5px solid rgba(124, 58, 237, .35);
  font-family: var(--mono); font-size: 11.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--violet-deep);
  transition: background .2s, color .2s, border-color .2s;
}
.ctl__clear:hover { background: var(--lilac); border-color: var(--violet); }
/* Plainly inert, not merely faded: no accent, no hover, and a cursor that
   says so before the click. Faded-only reads as "loading" to some people. */
.ctl__clear[disabled] {
  background: var(--cream-2);
  border-color: var(--line);
  color: var(--muted);
  cursor: not-allowed;
}
.ctl__clear[disabled]:hover { background: var(--cream-2); border-color: var(--line); }
:root[data-theme="dark"] .ctl__clear { color: var(--violet); border-color: rgba(182, 255, 58, .4); }

/* A fieldset carries a UA border, padding and, worse, a min-width of
   min-content that refuses to shrink inside a grid track. All three go. */
.ctl__group {
  border: 0; padding: 0; margin: 0;
  min-width: 0;
}
.ctl__legend {
  padding: 0;
  margin-bottom: 9px;
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--muted);
}

.ctl__split {
  display: grid;
  gap: clamp(14px, 1.8vw, 20px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}

.chips { display: flex; flex-wrap: wrap; gap: 8px; }

/* Every chip carries a hollow ring that fills when it is on. The ring is a
   fixed width in both states, so toggling a chip never rewraps the row, and
   "on" survives being seen without colour. Hover only tints. */
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 38px;
  padding: 7px 15px;
  border-radius: 999px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 13.5px; font-weight: 600; line-height: 1.2;
  transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
}
.chip::before {
  content: ''; flex: none;
  width: 10px; height: 10px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  background: transparent;
  transition: background .2s;
}
.chip:hover { background: var(--lilac); border-color: rgba(124, 58, 237, .4); color: var(--violet-deep); }
.chip[aria-pressed="true"] {
  background: var(--violet);
  border-color: var(--violet);
  color: #fff;
  box-shadow: 0 8px 18px -10px rgba(124, 58, 237, .7);
}
.chip[aria-pressed="true"]::before { background: currentColor; }
.chip[aria-pressed="true"]:hover { background: var(--violet-deep); border-color: var(--violet-deep); color: #fff; }
:root[data-theme="dark"] .chip[aria-pressed="true"],
:root[data-theme="dark"] .chip[aria-pressed="true"]:hover {
  color: #04120b;
  box-shadow: 0 0 20px -6px rgba(182, 255, 58, .6);
}
:root[data-theme="dark"] .chip:hover { color: var(--violet-deep); }

/* The two toggles that change the answer most: "can fund web and IT" and
   "open now". They start already tinted so they read as offers, not as two
   more of the twelve audience chips above them. */
.chip--key {
  min-height: 44px;
  padding: 9px 18px;
  font-size: 14px;
  background: var(--lilac);
  border-color: rgba(124, 58, 237, .3);
  color: var(--violet-deep);
}
.chip--key:hover { background: rgba(124, 58, 237, .16); }
:root[data-theme="dark"] .chip--key { color: var(--violet); border-color: rgba(182, 255, 58, .35); }
:root[data-theme="dark"] .chip--key:hover { background: rgba(182, 255, 58, .2); }

.ctl__row--toggles { padding-top: 2px; border-top: 1px dashed var(--line); }
.ctl__count {
  margin-left: auto;
  font-family: var(--mono); font-size: 12px; letter-spacing: .04em;
  color: var(--muted);
}

/* Deliberately NOT sticky. Twelve audience chips plus location, type, the two
   toggles and the search field measure 420px, and with the 70px nav that is
   490px of permanent furniture: 64 percent of a 1366x768 laptop, leaving
   under 280px to read results in. Filtering here is something people do once
   and then browse, so the controls scroll away like any other block and the
   whole window belongs to the programs. */

/* ── Results ────────────────────────────────────────────────── */
.results { padding: clamp(20px, 3vw, 34px) 0 clamp(40px, 6vw, 72px); }

/* auto-fill, not auto-fit: with auto-fit a single search result stretches
   into one 1220px slab. minmax(min(100%, 330px), 1fr), never
   minmax(330px, 1fr), or the track outgrows a 360px phone and the whole
   page scrolls sideways. Same lesson as the tables in css/terms.css. */
.plist {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr));
  gap: clamp(14px, 1.8vw, 22px);
  /* stretch, not start: the card is a flex column whose foot carries
     margin-top:auto, so matching the row height is what pins every Details
     button and verified date onto one line instead of a ragged edge. */
  align-items: stretch;
}

.notice {
  display: flex;
  margin-bottom: 22px;
  padding: 14px 18px;
  border-left: 3px solid #B3261E;
  border-radius: 0 var(--r) var(--r) 0;
  background: rgba(179, 38, 30, .08);
  color: var(--ink); font-size: 14.5px;
}
:root[data-theme="dark"] .notice { border-left-color: #ff8f7a; background: rgba(255, 143, 122, .1); }

/* ── One program card ───────────────────────────────────────── */
/* No blob layer and no blur on these, unlike the store's .card: forty of
   them can be on screen at once and forty blurred pseudo-elements is a
   measurable scroll cost on a phone. The status bar carries the colour. */
.pcard {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  gap: 12px;
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  padding: clamp(20px, 2.2vw, 26px);
  box-shadow: var(--shadow-sm);
  overflow-wrap: break-word;
  scroll-margin-top: calc(var(--nav-h) + 16px);
  transition: transform .35s var(--ease), border-color .35s, box-shadow .35s;
  --pc-acc: var(--muted);
}
.pcard::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 4px;
  background: var(--pc-acc);
}
.pcard:hover {
  transform: translateY(-4px);
  border-color: rgba(124, 58, 237, .22);
  box-shadow: var(--shadow-lg);
}
:root[data-theme="dark"] .pcard:hover { border-color: rgba(0, 255, 156, .3); }

/* The status bar repeats what the chip already says. It is redundant on
   purpose: at a glance down a column of cards the bar is the only thing
   readable, and the chip is there for anyone reading one card properly. */
.pcard[data-status="open"]             { --pc-acc: var(--green); }
.pcard[data-status="opens_soon"]       { --pc-acc: var(--violet); }
.pcard[data-status="rolling"]          { --pc-acc: var(--violet-bright); }
.pcard[data-status="watch"]            { --pc-acc: var(--amber); }
.pcard[data-status="closed_recurring"] { --pc-acc: var(--line); }

.pcard__head {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  justify-content: space-between; gap: 10px 14px;
}
.pcard__titles { min-width: 0; flex: 1 1 190px; }
.pcard__name {
  font-size: clamp(18px, 1.7vw, 21px); font-weight: 700;
  letter-spacing: -.015em; line-height: 1.25;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.pcard__funder {
  margin-top: 3px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .04em;
  line-height: 1.5;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* ── Deadline chip ──────────────────────────────────────────── */
/* Six tones, six SHAPES. The leading mark is a filled dot, a hollow ring, a
   bar, a diamond or a hollow square depending on status, and the border
   goes solid, dashed or dotted alongside it. Anyone who cannot separate
   amber from green still gets the difference between "closes in 9 days"
   and "closed, see cycle", which is the only thing on the card that can
   cost someone real money. */
.pchip {
  position: relative;
  display: inline-flex; align-items: center; gap: 7px;
  flex: none;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1.5px solid currentColor;
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  letter-spacing: .06em; line-height: 1.5;
  white-space: nowrap;
}
.pchip::before {
  content: ''; flex: none;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: currentColor;
}

/* soon: the only one with a filled plate, the heaviest type and a pulse.
   The brown ink is hardcoded because no token clears 4.5:1 on --sun; at
   11px that matters more than palette purity. */
.pchip--soon {
  background: var(--sun);
  border-color: var(--sun);
  color: #5C3B00;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  box-shadow: 0 6px 16px -8px rgba(240, 163, 26, .8);
}
.pchip--soon::before { animation: chipPulse 1.6s ease-in-out infinite; }
@keyframes chipPulse { 50% { opacity: .35; transform: scale(.7); } }
:root[data-theme="dark"] .pchip--soon {
  color: #120d00;
  box-shadow: 0 0 18px -4px rgba(255, 214, 10, .7);
}

/* open: solid border, filled dot */
.pchip--open { color: var(--green-deep); background: rgba(46, 212, 127, .12); }

/* opens: dashed border, hollow ring */
.pchip--opens {
  color: var(--violet-deep);
  border-style: dashed;
  background: var(--lilac);
}
.pchip--opens::before { background: transparent; box-shadow: inset 0 0 0 2px currentColor; }

/* rolling: no deadline at all, so the mark is a bar rather than a point */
.pchip--rolling { color: var(--ink-2); background: var(--cream-2); }
.pchip--rolling::before { width: 13px; height: 3px; border-radius: 2px; }

/* watch: dotted border, diamond mark */
.pchip--watch {
  color: var(--amber-deep);
  border-style: dotted;
  border-width: 2px;
  background: rgba(255, 201, 51, .16);
}
.pchip--watch::before { border-radius: 2px; transform: rotate(45deg); }
:root[data-theme="dark"] .pchip--watch { background: rgba(255, 214, 10, .1); }

/* closed: hollow square, lightest weight, no fill. It should be the
   quietest thing on the card without disappearing. */
.pchip--closed {
  color: var(--muted);
  border-color: var(--line);
  font-weight: 500;
}
.pchip--closed::before {
  border-radius: 1px;
  background: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

/* ── Tags ───────────────────────────────────────────────────── */
.ptags { display: flex; flex-wrap: wrap; gap: 6px; }
.ptag {
  padding: 3px 10px;
  border-radius: 7px;
  background: var(--cream-2);
  border: 1px solid transparent;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em;
  color: var(--ink-2);
  line-height: 1.7;
}
.ptag--loc  { font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.ptag--area { color: var(--muted); }
.ptag--type { border-color: var(--line); background: transparent; }

/* What the entry is FOR, as opposed to where it is and what kind of help it
   is. Tinted rather than outlined so a card carrying three of them still reads
   as one group, and distinguishable from the location and type tags without
   competing with the tech tag below. --lilac is already a lime tint under the
   dark theme, so this needs no separate dark rule beyond the text colour. */
.ptag--ind {
  background: var(--lilac);
  border-color: rgba(124, 58, 237, .28);
  color: var(--violet-deep);
  font-weight: 600;
}
:root[data-theme="dark"] .ptag--ind {
  border-color: rgba(182, 255, 58, .3);
  color: var(--violet-deep);
}

/* The one tag that answers "can this pay for my website". It is why most
   people opened the page, so it gets the brand gradient border, a tick and
   a weight nothing else on the card is allowed to have. */
.ptag--tech {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--green-deep);
  border: 1.5px solid transparent;
  border-radius: 999px;
  padding: 3px 12px;
  background:
    linear-gradient(var(--paper), var(--paper)) padding-box,
    var(--grad-brand) border-box;
  box-shadow: 0 4px 12px -8px rgba(23, 161, 94, .8);
}
.ptag--tech::before { content: '\2713'; font-size: 12px; line-height: 1; }
:root[data-theme="dark"] .ptag--tech { box-shadow: 0 0 14px -6px rgba(0, 255, 156, .7); }

/* ── Card body text ─────────────────────────────────────────── */
.pcard__amount {
  font-family: var(--mono); font-size: 14px; font-weight: 700;
  letter-spacing: -.01em;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* Two lines while collapsed keeps every card in a row roughly the same
   height, so the grid does not turn into a ragged staircase. Opening the
   card is what releases it, which is also what the Details button promises. */
.pcard__elig {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  color: var(--ink-2);
  font-size: 14.2px; line-height: 1.6;
}
.pcard.is-open .pcard__elig {
  display: block;
  -webkit-line-clamp: none;
  line-clamp: none;
  overflow: visible;
}

.pcard__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
}
/* Fixed width so the row does not jump when the label swaps between
   "Details" and "Hide details". */
.pcard__toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-width: 132px; min-height: 38px;
  padding: 7px 16px;
  border-radius: 999px;
  border: 1.5px solid rgba(124, 58, 237, .35);
  font-family: var(--mono); font-size: 11.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--violet-deep);
  transition: background .2s, border-color .2s, color .2s;
}
.pcard__toggle::after {
  content: '\25BE';
  font-size: 10px; line-height: 1;
  transition: transform .25s var(--ease);
}
.pcard__toggle:hover { background: var(--lilac); border-color: var(--violet); }
.pcard.is-open .pcard__toggle::after { transform: rotate(180deg); }
:root[data-theme="dark"] .pcard__toggle { color: var(--violet); border-color: rgba(182, 255, 58, .4); }

.pcard__ver {
  margin-left: auto;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .04em;
  color: var(--muted);
}

.pcard__body { display: grid; gap: 16px; padding-top: 2px; }

.pdetails { display: grid; gap: 12px; }
.pdetail { display: grid; gap: 3px; }
.pdetail__label {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--violet-deep);
}
.pdetail__value {
  color: var(--ink-2);
  font-size: 14.2px; line-height: 1.6;
  overflow-wrap: anywhere;
}
:root[data-theme="dark"] .pdetail__label { color: var(--violet); }

.pcard__actions { display: flex; flex-wrap: wrap; gap: 10px; }
/* The shared .btn is sized for a hero. Inside a card it needs to sit under
   a paragraph without shouting over the card next to it. */
.pcard__actions .btn { flex: 1 1 auto; padding: 10px 18px; font-size: 14px; }
.pcard__actions .btn--solid { box-shadow: 0 10px 22px -14px rgba(23, 161, 94, .7); }

/* 1.8 seconds of confirmation, set by js/grants.js. Green because the
   thing it confirms succeeded, and bordered because the button keeps its
   ghost shape while the label changes. */
.pcard__copy.is-copied {
  background: rgba(46, 212, 127, .18);
  border-color: var(--green);
  color: var(--green-deep);
}
:root[data-theme="dark"] .pcard__copy.is-copied {
  background: rgba(0, 255, 156, .14);
  border-color: var(--green);
  color: var(--green);
}

/* A shared link drops you into the middle of a long grid, so the card you
   landed on says so and keeps saying so. The pulse starts and ends on the
   resting ring, which is what lets the reduced-motion block below collapse
   it to nothing without leaving the card mid-animation. */
.pcard.is-linked {
  border-color: var(--violet);
  box-shadow: var(--shadow-lg), 0 0 0 3px rgba(124, 58, 237, .3);
  animation: linkPing 2.6s var(--ease) 1;
}
@keyframes linkPing {
  0%, 100% { box-shadow: var(--shadow-lg), 0 0 0 3px rgba(124, 58, 237, .3); }
  35%      { box-shadow: var(--shadow-lg), 0 0 0 10px rgba(124, 58, 237, .14); }
}
:root[data-theme="dark"] .pcard.is-linked {
  box-shadow: var(--shadow-lg), 0 0 0 3px rgba(182, 255, 58, .4);
  animation-name: linkPingDark;
}
@keyframes linkPingDark {
  0%, 100% { box-shadow: var(--shadow-lg), 0 0 0 3px rgba(182, 255, 58, .4); }
  35%      { box-shadow: var(--shadow-lg), 0 0 0 10px rgba(182, 255, 58, .16); }
}

/* ── The pinned program ─────────────────────────────────────── */
/* GenieSolos's own offer, sitting above the results rather than inside them.
   It has to read as clearly NOT a program card, because everything else on
   this page is somebody else's money: no status chip, no tags, no verified
   line, and a left rule in the store's violet instead of the paper-and-shadow
   the cards use. It is a sibling of .plist, so js/grants.js never moves it,
   never counts it, and it survives every filter and the empty state. */
.pin {
  display: grid;
  gap: 10px;
  justify-items: start;
  margin-bottom: 22px;
  padding: clamp(18px, 2.2vw, 26px) clamp(18px, 2.4vw, 28px);
  background: var(--band);
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--violet);
  border-radius: var(--r);
}
.pin__eyebrow {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--violet-deep);
}
.pin__title {
  font-family: var(--serif); font-style: italic; font-weight: 600;
  font-size: clamp(20px, 2.4vw, 26px); line-height: 1.15;
  color: var(--ink);
}
.pin__body { max-width: 72ch; color: var(--ink-2); font-size: 14.8px; }
.pin__fine { max-width: 72ch; color: var(--muted); font-size: 12.8px; }
:root[data-theme="dark"] .pin__eyebrow { color: var(--violet); }

/* The block itself never animates; this only stops the button's hover and
   focus transitions for anyone who has asked the OS for less movement. */
@media (prefers-reduced-motion: reduce) {
  .pin,
  .pin .btn { transition: none; }
}

/* ── The one ask ────────────────────────────────────────────── */
/* js/grants.js moves #ctaBlock into .plist after the sixth card, so it has
   to span the row rather than pose as a seventh program. Band fill, dashed
   edge, no shadow and no hover: it is deliberately the calmest card in the
   grid, because a loud one here would read as an ad in a public directory. */
.cta {
  grid-column: 1 / -1;
  display: grid;
  gap: 12px;
  justify-items: start;
  background: var(--band);
  border: 1px dashed var(--line);
  border-radius: var(--r);
  padding: clamp(20px, 2.4vw, 28px);
}
.cta__eyebrow {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--violet-deep);
}
.cta__body { max-width: 72ch; color: var(--ink-2); font-size: 14.8px; }
:root[data-theme="dark"] .cta__eyebrow { color: var(--violet); }

/* ── Empty state ────────────────────────────────────────────── */
.empty {
  display: grid; gap: 10px; justify-items: center;
  text-align: center;
  margin-top: 26px;
  padding: clamp(36px, 6vw, 62px) clamp(20px, 4vw, 40px);
  border: 1px dashed var(--line);
  border-radius: var(--r-lg);
  background: var(--band);
  color: var(--ink-2);
}
.empty__title {
  font-family: var(--serif); font-style: italic; font-weight: 600;
  font-size: clamp(21px, 2.6vw, 28px); line-height: 1.2;
  color: var(--ink);
}
.empty p { max-width: 52ch; font-size: 14.6px; }
.empty a {
  color: var(--violet); font-weight: 600;
  border-bottom: 1px dashed rgba(124, 58, 237, .45);
  transition: color .2s, border-color .2s;
}
.empty a:hover { color: var(--green-deep); border-color: var(--green-deep); }
:root[data-theme="dark"] .empty a { border-bottom-color: rgba(182, 255, 58, .5); }

/* ── Tail: the ask and the disclaimer ───────────────────────── */
.tail {
  background: var(--band);
  box-shadow: inset 0 1px 0 var(--line-soft), inset 0 -1px 0 var(--line-soft);
  padding: clamp(34px, 5vw, 56px) 0;
}
.tail__ask { font-size: 15.5px; color: var(--ink); }
.tail__ask a {
  color: var(--violet); font-weight: 600;
  border-bottom: 1px dashed rgba(124, 58, 237, .45);
  overflow-wrap: anywhere;
}
.tail__ask a:hover { color: var(--green-deep); border-color: var(--green-deep); }
:root[data-theme="dark"] .tail__ask a { border-bottom-color: rgba(182, 255, 58, .5); }

/* Real legal text, so it is small but never grey-on-grey: --muted clears
   4.5:1 on the band in both themes. */
.tail__legal {
  margin-top: 14px;
  max-width: 92ch;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.85;
  color: var(--muted);
}

/* ── Footer: the same plum evening as the homepage ──────────── */
.foot {
  position: relative; overflow: hidden;
  background: #241F35;
  color: #F6F1E6;
  padding: 56px 0 48px;
  text-align: center;
}
:root[data-theme="dark"] .foot { background: var(--band); border-top: 1px solid var(--line-soft); }
.foot::before, .foot::after {
  content: ''; position: absolute; pointer-events: none; filter: blur(52px);
}
.foot::before {
  top: -110px; left: -80px; width: 360px; aspect-ratio: 1;
  background: radial-gradient(circle, rgba(46, 212, 127, .2), transparent 70%);
  border-radius: var(--blob-a);
}
.foot::after {
  bottom: -140px; right: -60px; width: 400px; aspect-ratio: 1;
  background: radial-gradient(circle, rgba(124, 58, 237, .3), transparent 70%);
  border-radius: var(--blob-c);
}
:root[data-theme="dark"] .foot::before { background: radial-gradient(circle, rgba(0, 255, 156, .16), transparent 70%); }
:root[data-theme="dark"] .foot::after  { background: radial-gradient(circle, rgba(255, 214, 10, .13), transparent 70%); }
.foot__inner { position: relative; z-index: 1; display: grid; gap: 8px; padding: 0 18px 40px; }
.foot__sig {
  font-family: var(--mono); font-weight: 700; font-size: 15px; letter-spacing: .2em;
  background: linear-gradient(90deg, var(--green-bright), var(--sun-bright) 55%, var(--violet-bright));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  width: fit-content; margin-inline: auto;
}
.foot__meta {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em;
  color: rgba(246, 241, 230, .66); text-transform: uppercase;
}
:root[data-theme="dark"] .foot__meta { color: var(--muted); }
.foot__contact { font-size: 13.5px; color: rgba(246, 241, 230, .8); }
:root[data-theme="dark"] .foot__contact { color: var(--ink-2); }
.foot__contact a { text-decoration: underline; text-underline-offset: 3px; }
.foot__contact a:hover { color: var(--sun-bright); }
.foot__home {
  margin-top: 6px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(246, 241, 230, .55);
}
:root[data-theme="dark"] .foot__home { color: var(--muted); }
.foot__home a:hover { color: var(--sun-bright); }

/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 860px) {
  .hero__fresh { font-size: 11.5px; }
  .pcard__head { gap: 8px 10px; }
}

@media (max-width: 560px) {
  .nav { gap: 8px; padding: 0 12px; }
  .nav__links a { padding: 8px 9px; font-size: 11.5px; letter-spacing: .06em; }
  .nav__end { gap: 8px; }
  .hero__title { font-size: clamp(32px, 10vw, 46px); }
  .hero__eyebrow { font-size: 10.5px; letter-spacing: .16em; }
  /* Full-width rows below this point: at 360px a two-up flex row leaves
     each half too narrow for its own label. */
  .ctl__search { flex: 1 1 100%; }
  .ctl__clear { flex: 1 1 100%; }
  .ctl__row--toggles .chip--key { flex: 1 1 100%; justify-content: center; }
  .ctl__count { margin-left: 0; flex: 1 1 100%; }
  .pcard__head { flex-direction: column; align-items: flex-start; }
  /* Turning the head into a column turns flex-basis from a width into a
     height, and .pcard__titles carries `flex: 1 1 190px`. Left alone it
     claims 190px of height and drops a blank band between the funder line
     and the status chip. */
  .pcard__titles { flex: 0 0 auto; width: 100%; }
  .pcard__toggle { flex: 1 1 100%; }
  .pcard__ver { margin-left: 0; flex: 1 1 100%; }
  .pcard__actions .btn { flex: 1 1 100%; }
}

/* ── Reduced motion ─────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    /* Zeroing the delay too, or the hero's staggered fadeUp holds its
       `from` frame (opacity 0) for up to half a second and the headline
       is simply missing for a visitor who asked for less motion. */
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }
}

/* ── Print: the directory, without the machinery ────────────── */
@media print {
  :root, :root[data-theme="dark"] {
    --cream: #fff; --paper: #fff; --band: #fff; --cream-2: #fff;
    --ink: #000; --ink-2: #1a1a1a; --muted: #444;
    --violet: #000; --violet-deep: #000; --lilac: #fff;
    --green-deep: #000; --amber-deep: #000;
    --line: #bbb; --line-soft: #ddd;
  }
  .nav, .skip, .controls, .hero__glow, .pcard__foot, .pcard__actions { display: none !important; }
  .hero::before, .foot::before, .foot::after { display: none !important; }
  .hero { padding: 10px 0 18px; }
  .results { padding: 0 0 18px; }
  /* Paper has no Details button, so every card prints fully open. */
  .pcard__body[hidden] { display: grid !important; }
  .pcard__elig { display: block; overflow: visible; }
  .plist { display: block; }
  .pcard { break-inside: avoid-page; box-shadow: none; border: 1px solid #ccc; margin-bottom: 12px; }
  .pchip { border-color: #000; background: none; box-shadow: none; }
  .ptag--tech { background: none; border: 1.5px solid #000; box-shadow: none; }
  .hero__title em, .nav__name, .foot__sig {
    background: none !important;
    -webkit-text-fill-color: initial !important;
    color: #000 !important;
  }
  .foot { background: #fff; color: #000; padding: 20px 0; }
  .foot__meta, .foot__contact, .foot__home { color: #333; }
}

/* ── Back to top ─────────────────────────────────────────────
   Lifted from css/style.css so it behaves and looks exactly like the button
   on the homepage. It earns its place here more than anywhere else on the
   site: this page is 300 cards long, and the filters live at the very top. */
.totop {
  position: fixed; right: 22px; bottom: 22px; z-index: 40;
  width: 50px; height: 50px; display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-soft);
  background: var(--paper);
  color: var(--violet);
  box-shadow: var(--shadow-md);
  opacity: 0; visibility: hidden; transform: translateY(14px);
  transition: .35s var(--ease);
}
.totop.show { opacity: 1; visibility: visible; transform: none; }
.totop:hover {
  background: var(--violet); color: #fff;
  border-color: var(--violet);
  transform: translateY(-3px);
  box-shadow: 0 18px 36px -14px rgba(124, 58, 237, .55);
}
/* --violet becomes acid lime on black, so white text on it would vanish. */
:root[data-theme="dark"] .totop:hover {
  color: #04120b;
  box-shadow: 0 0 24px -4px rgba(182, 255, 58, .6);
}
/* The button is fixed over the bottom right corner, which on a phone is
   exactly where the last card's Details button sits. */
@media (max-width: 560px) {
  .totop { right: 14px; bottom: 14px; width: 44px; height: 44px; }
}
@media print { .totop { display: none; } }
