/* Self-hosted so the page makes no third-party request. These were served from
   fonts.googleapis.com, which sent every visitor's IP and user-agent to Google
   and couldn't carry Subresource Integrity (the response varies per UA).
   Both faces are SIL OFL 1.1 — licences sit beside the files in assets/fonts/.

   Same subsets Google served, minus Rajdhani's devanagari: the site is
   English-only, so those three files were dead weight. unicode-range is kept
   as it was, so a browser only pulls latin-ext if a character calls for it. */

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(assets/fonts/rajdhani-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(assets/fonts/rajdhani-500-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(assets/fonts/rajdhani-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(assets/fonts/rajdhani-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(assets/fonts/rajdhani-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(assets/fonts/rajdhani-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Share Tech Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(assets/fonts/share-tech-mono-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Without this the browser assumes a light page and paints the default light
     scrollbar down the side of an otherwise black site. */
  color-scheme: dark;

  --bg: #0b0d0b;
  --bg-deep: #070907;
  --panel: rgba(15, 18, 14, 0.68);
  --panel-strong: rgba(13, 16, 12, 0.88);
  --text: #d6dacb;
  --muted: #808777;
  --olive: #9aa084;
  --olive-dim: #5e6551;
  /* Dimmest tone that still clears WCAG AA (4.5:1) for small text on --bg;
     measures 5.53:1. Use this for small labels rather than --olive-dim,
     which is only 3.21:1 and fails. */
  --label: #848b79;
  --line: rgba(154, 160, 132, 0.28);
  --amber: #d08b2f;
  --cyan: #6cb7bd;
  --quiet-y: 0px;
  --quiet-opacity: 1;
  --quiet-scale: 0.96;
}

* {
  box-sizing: border-box;
}

/* The UA default ring is drawn from the browser or OS accent colour, so it
   varies per visitor and some of those land close to the olive chrome. Pinning
   it to the amber accent makes the keyboard path read the same everywhere.
   :focus-visible rather than :focus keeps the ring off mouse clicks. */
:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
}

html {
  scroll-behavior: smooth;
  background: var(--bg);
}

body {
  margin: 0;
  min-width: 320px;
  color: var(--text);
  background:
    radial-gradient(circle at 73% 35%, rgba(89, 75, 57, 0.19), transparent 26%),
    radial-gradient(circle at 63% 62%, rgba(83, 91, 68, 0.10), transparent 32%),
    linear-gradient(180deg, #111310 0%, var(--bg) 43%, var(--bg-deep) 100%);
  font-family: "Share Tech Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  overflow-x: hidden;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -4;
  pointer-events: none;
  background:
    linear-gradient(rgba(145, 154, 124, 0.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(145, 154, 124, 0.025) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: linear-gradient(to bottom, black, transparent 82%);
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 35%, rgba(0, 0, 0, 0.24) 70%, rgba(0, 0, 0, 0.64) 100%);
}

::selection {
  background: var(--olive);
  color: #0a0c09;
}

/* Subtle late-80s terminal bloom beneath the grain/scanline layers. */
.phosphor-glow {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(circle at 42% 35%, rgba(154, 160, 132, 0.035), transparent 36%),
    linear-gradient(180deg, rgba(130, 145, 112, 0.018), transparent 42%);
  mix-blend-mode: screen;
}

.noise {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 2;
  pointer-events: none;
  /* Eased back now the grain is finer — the old value was carrying a much
     blockier texture, so the same opacity reads as busier than it should. */
  opacity: 0.046;
  mix-blend-mode: screen;
  image-rendering: pixelated;
  filter: contrast(1.14);
}

/* Animated CRT grain sits above Quiet/background but below the site UI.
   The canvas is regenerated by script.js, so the static genuinely changes frame
   to frame instead of sliding a single texture around. */

/* Tighter pitch (3px rather than 4px) and a stronger line: the old setting
   worked out to an effective 0.0019 alpha, which all but vanished at 1080p.
   Two stacked gradients — a bright scan and a dark gap — so the banding reads
   as a CRT rather than an overall haze. */
.scanlines {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0.5;
  background:
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.16) 0,
      rgba(0, 0, 0, 0.16) 1px,
      transparent 1px,
      transparent 3px
    ),
    repeating-linear-gradient(
      to bottom,
      transparent 0,
      transparent 2px,
      rgba(200, 226, 190, 0.05) 3px
    );
}

.shell {
  width: min(1180px, calc(100% - 64px));
  margin-inline: auto;
  position: relative;
  z-index: 4;
}

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 8;
  height: 72px;
  padding: 0 clamp(24px, 4vw, 72px);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* The blur lives on a pseudo-element rather than the bar itself, so it can be
   masked to fade out gradually — masking .topbar directly would fade the brand
   and status text with it. It also extends past the bar's height, so the blur
   ramps off instead of ending on a hard edge. */
.topbar::before {
  content: "";
  position: absolute;
  inset: 0 0 -46px;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(7, 9, 7, 0.88), rgba(7, 9, 7, 0) 82%);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  -webkit-mask-image: linear-gradient(to bottom, #000 0, rgba(0, 0, 0, 0.75) 42%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, rgba(0, 0, 0, 0.75) 42%, transparent 100%);
}

.brand-mini,
.status {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--olive);
  font-size: 0.76rem;
  letter-spacing: 0.16em;
  text-decoration: none;
}

.brand-mark {
  width: 12px;
  height: 12px;
  border: 1px solid var(--olive);
  transform: rotate(45deg);
  box-shadow: inset 0 0 0 3px rgba(154, 160, 132, 0.08);
}

.status-dot {
  width: 6px;
  height: 6px;
  background: var(--amber);
  border-radius: 50%;
  box-shadow: 0 0 12px rgba(208, 139, 47, 0.65);
}

.quiet-wrap {
  position: fixed;
  z-index: 1;
  /* Pulled in from the right so she sits between centre and the corner. The
     offset is derived from the text column rather than raw vw: she moves in
     as far as the space allows and stops at the edge of the hero copy, so
     wide screens centre her more while narrow ones keep the original spot. */
  right: max(-52px, calc(50vw - 820px));
  bottom: -10vh;
  width: min(46vw, 720px);
  height: 112vh;
  pointer-events: none;
  transform: translate3d(0, var(--quiet-y), 0) scale(var(--quiet-scale));
  transform-origin: right bottom;
  opacity: var(--quiet-opacity);
  will-change: transform, opacity;
  filter: saturate(0.88) contrast(1.03) brightness(0.95);
}

.quiet-wrap::before {
  content: "";
  position: absolute;
  inset: 7% -8% -4% 15%;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(66, 59, 46, 0.24), transparent 68%);
  filter: blur(24px);
}

.quiet {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: right bottom;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* .shell's z-index is dropped here so the hero's parts can stack individually
   against Quiet. As one layer at z-index 4 the frame was locked to the same
   level as the copy, so nothing could put its rules behind her without taking
   the text with them. */
.hero {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-top: 92px;
  padding-bottom: 70px;
  z-index: auto;
}

/* Dossier frame around the hero, with crosshair ticks at the corners. Left at
   z-index auto so the border and ticks paint below Quiet (z-index 1); the copy
   and status bar below opt back above her. */
.hero-frame {
  position: relative;
  width: 100%;
  padding: 34px 38px 30px;
  border: 1px solid rgba(154, 160, 132, 0.16);
}

.hero-frame::before,
.hero-frame::after {
  content: "";
  position: absolute;
  width: 13px;
  height: 13px;
  pointer-events: none;
  background:
    linear-gradient(var(--olive-dim), var(--olive-dim)) center / 100% 1px no-repeat,
    linear-gradient(var(--olive-dim), var(--olive-dim)) center / 1px 100% no-repeat;
  opacity: 0.75;
}

.hero-frame::before {
  top: -7px;
  left: -7px;
}

.hero-frame::after {
  right: -7px;
  bottom: -7px;
}

.hero-copy {
  position: relative;
  z-index: 4;
  max-width: 720px;
  padding: 6px 0 0;
}

/* Measuring-tape ticks running off the amber bar. Left below Quiet with the
   frame: the bar stretches the full width of the hero, so its box rules run
   out across her even though the cells themselves stop well short. */
.hero-status {
  display: flex;
  flex-wrap: wrap;
  margin-top: 30px;
  border: 1px solid rgba(154, 160, 132, 0.14);
  color: var(--label);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
}

.hero-status span {
  padding: 10px 18px 9px;
  border-right: 1px solid rgba(154, 160, 132, 0.14);
}

.hero-status span:last-child {
  border-right: 0;
}

.hero-status b {
  margin-right: 12px;
  color: #8b9280;
  font-weight: 400;
}

.btn-icon {
  width: 15px;
  height: 15px;
  margin-left: 10px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.3;
}

.eyebrow {
  margin: 0 0 22px;
  color: var(--label);
  font-size: clamp(0.68rem, 1vw, 0.82rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 24px;
  font-family: "Rajdhani", system-ui, sans-serif;
  font-size: clamp(4.1rem, 8.2vw, 8.7rem);
  line-height: 0.72;
  letter-spacing: -0.055em;
  font-weight: 700;
  color: #cdd2c1;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(255,255,255,0.025);
}

h1 span {
  display: block;
}

h1 .projects {
  margin-top: 0.22em;
  font-size: 0.53em;
  line-height: 0.9;
  letter-spacing: 0.28em;
  font-weight: 500;
  color: #b8bdad;
}

.rule {
  position: relative;
  width: min(660px, 100%);
  height: 18px;
}

/* Ruler ticks running off the amber bar, as on the reference. */
.rule::after {
  content: "";
  position: absolute;
  left: 76px;
  right: 0;
  top: 0;
  height: 9px;
  background:
    linear-gradient(to right, var(--line) 0%, var(--line) 78%, transparent 100%) top / 100% 1px no-repeat,
    repeating-linear-gradient(
      to right,
      rgba(154, 160, 132, 0.45) 0 1px,
      transparent 1px 9px
    ) top / 100% 100% no-repeat;
  mask-image: linear-gradient(to right, #000 0, #000 62%, transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 62%, transparent 100%);
}

.rule::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 76px;
  height: 3px;
  background: var(--amber);
}

.subhead {
  max-width: 620px;
  margin: 10px 0 30px;
  color: #929987;
  font-size: clamp(0.86rem, 1.35vw, 1rem);
  line-height: 1.8;
  letter-spacing: 0.075em;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
}

.button {
  position: relative;
  min-width: 165px;
  padding: 13px 18px 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  color: var(--text);
  text-decoration: none;
  font-family: "Rajdhani", system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: 0.12em;
  font-size: 0.84rem;
  transition: border-color 160ms ease, background 160ms ease, color 160ms ease, transform 160ms ease;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}

.button:hover {
  transform: translateY(-2px);
  border-color: rgba(195, 201, 172, 0.6);
}

.button.primary {
  background: rgba(154, 160, 132, 0.13);
}

.button.primary:hover {
  background: rgba(154, 160, 132, 0.22);
}

.button.ghost {
  color: var(--muted);
}

/* Updates terminal --------------------------------------------------------
   Reads updates.txt on load and rolls the entries up through a fixed window,
   like output streaming in a CMD prompt. The frame holds one size whatever
   the file contains — see .term-view. */
.term {
  position: relative;
  width: min(560px, 100%);
  margin-top: 52px;
  padding: 16px 22px 19px;
  border: 1px solid rgba(154, 160, 132, 0.15);
  background:
    linear-gradient(135deg, rgba(154, 160, 132, 0.04), transparent 52%),
    rgba(8, 10, 8, 0.5);
  box-shadow: inset 2px 0 0 rgba(154, 160, 132, 0.05);
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
}

.term-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 13px;
  padding-bottom: 11px;
  border-bottom: 1px solid rgba(154, 160, 132, 0.12);
}

.term-title {
  color: var(--amber);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
}

.term-state {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #7d8472;
  font-size: 0.58rem;
  letter-spacing: 0.18em;
}

/* Static path line above the rolling feed. */
.term-path {
  margin: 0 0 11px;
  color: var(--amber);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  opacity: 0.85;
}

.term-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #7fbf6a;
  box-shadow: 0 0 9px rgba(127, 191, 106, 0.65);
  animation: term-blink 2.4s steps(1, end) infinite;
}

@keyframes term-blink {
  0%, 62% { opacity: 1; }
  63%, 100% { opacity: 0.18; }
}

/* Fixed height, so the panel is one size regardless of how much is in
   updates.txt — roughly thirteen lines, with the overflow rolling through.

   The roll used to be a CSS transform on .term-reel, which meant the window
   could not be scrolled by hand — a transform and a scroll offset are separate
   things, and the transform always won. It is a real scroll offset now, driven
   from script.js, so the automatic roll and dragging the bar are the same
   mechanism and hand off to each other cleanly.

   scroll-behavior has to stay auto: html sets it to smooth, and although it
   isn't inherited, a smooth-scrolled wrap would visibly slide the seam. */
.term-view {
  height: 24em;
  overflow-y: auto;
  scroll-behavior: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(154, 160, 132, 0.32) transparent;
  font-size: clamp(0.84rem, 1.3vw, 0.96rem);
  line-height: 1.85;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 15%, #000 85%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 15%, #000 85%, transparent 100%);
}

.term-view::-webkit-scrollbar {
  width: 6px;
}

.term-view::-webkit-scrollbar-thumb {
  background: rgba(154, 160, 132, 0.32);
}

.term-view::-webkit-scrollbar-track {
  background: transparent;
}

.term-entry {
  padding-bottom: 0.95em;
}

/* Hanging indent: the prompt sits in the left gutter and wrapped text lines
   up with the first character after it. */
.term-line {
  margin: 0;
  padding-left: 3em;
  color: #a9b09d;
  letter-spacing: 0.04em;
  text-indent: -3em;
}

/* Continuation lines carry no prompt, so they start at the gutter edge. */
.term-cont {
  color: #8d947f;
  text-indent: 0;
}

.term-prompt {
  margin-right: 0.55em;
  color: var(--amber);
  opacity: 0.9;
}

/* Credits panel above the footer. Same terminal frame as the updates feed,
   only wider and shorter — see credits.txt for the names it rolls. */
.credits {
  padding-bottom: 46px;
}

.term-wide {
  width: 100%;
  margin-top: 0;
}

.term-view-short {
  height: 11em;
}

.resources {
  min-height: 86vh;
  padding-top: 120px;
  padding-bottom: 140px;
}

.section-heading {
  max-width: 880px;
  padding-bottom: 22px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  border-bottom: 1px solid var(--line);
}

.section-heading h2 {
  margin: 0;
  font-family: "Rajdhani", system-ui, sans-serif;
  font-size: clamp(2.4rem, 5vw, 4.8rem);
  line-height: 0.95;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #c8ccbc;
}

.section-heading .eyebrow {
  margin-bottom: 9px;
}

.section-code {
  color: var(--label);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
}


/* Archive project layout --------------------------------------------------
   Dossier rows: index chip, copy, then a status badge and action icons
   pinned right. */
.project-list {
  width: min(880px, 100%);
  display: grid;
  gap: 12px;
  margin-top: 18px;
}

.project-card {
  position: relative;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 20px;
  align-items: start;
  padding: 20px 22px 21px;
  border: 1px solid rgba(154, 160, 132, 0.17);
  background:
    linear-gradient(135deg, rgba(154, 160, 132, 0.028), transparent 42%),
    rgba(8, 10, 8, 0.68);
  box-shadow: inset 2px 0 0 rgba(154, 160, 132, 0.04);
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  transition: border-color 160ms ease, background 160ms ease;
}

.project-card:hover {
  border-color: rgba(154, 160, 132, 0.34);
  background:
    linear-gradient(135deg, rgba(154, 160, 132, 0.05), transparent 42%),
    rgba(10, 13, 10, 0.74);
}

.project-card::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 44px;
  height: 1px;
  background: var(--olive-dim);
  opacity: 0.55;
}

.project-index {
  padding: 3px 0 0;
  color: var(--label);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
}

.project-main {
  min-width: 0;
}

.project-main .resource-type {
  margin-bottom: 7px;
}

.project-card h3 {
  margin: 0 0 9px;
  font-family: "Rajdhani", system-ui, sans-serif;
  color: #c8ccbc;
  font-size: clamp(1.15rem, 1.8vw, 1.42rem);
  line-height: 1.08;
  letter-spacing: 0.015em;
}

.project-card p {
  margin: 0;
  color: #858c7d;
  font-size: 0.76rem;
  line-height: 1.72;
  letter-spacing: 0.025em;
}

.project-card code {
  color: #a8ae9e;
  font: inherit;
}

.project-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
}

.project-badge {
  padding: 6px 11px 5px;
  border: 1px solid rgba(154, 160, 132, 0.3);
  color: #9ca68f;
  font-size: 0.58rem;
  letter-spacing: 0.18em;
  white-space: nowrap;
  clip-path: polygon(5px 0, 100% 0, 100% calc(100% - 5px), calc(100% - 5px) 100%, 0 100%, 0 5px);
}

.project-badge.upcoming {
  border-color: rgba(208, 139, 47, 0.4);
  color: #b89a5f;
}

.project-actions {
  display: flex;
  gap: 8px;
}

.icon-btn {
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(154, 160, 132, 0.2);
  color: #9ca68f;
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
}

.icon-btn:hover {
  border-color: rgba(195, 201, 172, 0.55);
  background: rgba(154, 160, 132, 0.1);
  color: #d0d5c2;
}

.icon-btn svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: square;
}

/* The credits panel follows straight after this section, so the tall
   min-height and deep bottom padding the other sections use would leave a
   dead band between the last card and the reel. */
.database-section {
  min-height: auto;
  padding-top: 105px;
  padding-bottom: 34px;
}

.database-card {
  max-width: 880px;
}

.resource-type {
  display: block;
  margin-bottom: 8px;
  color: var(--amber);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
}

/* Bare quote above the footer — no panel, just type matching the body copy. */
.quoteline {
  padding-bottom: 30px;
  opacity: 1;
  transition: opacity 620ms ease;
}

.quoteline.is-out {
  opacity: 0;
}

.quoteline-text {
  max-width: 620px;
  margin: 0 0 7px;
  color: #7d8474;
  font-size: 0.82rem;
  line-height: 1.8;
  letter-spacing: 0.05em;
}

.quoteline-text::before {
  content: "\201C";
  color: var(--olive-dim);
}

.quoteline-text::after {
  content: "\201D";
  margin-left: 2px;
  color: var(--olive-dim);
}

.quoteline-attr {
  margin: 0;
  /* --olive-dim measures 3.21:1 here and fails AA; --label is the dimmest tone
     that still clears it. See the note in :root. */
  color: var(--label);
  font-family: "Rajdhani", system-ui, sans-serif;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.quoteline-attr::before {
  content: "— ";
}

.footer {
  min-height: 110px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--line);
  color: var(--label);
  font-size: 0.65rem;
  letter-spacing: 0.15em;
}

@media (max-width: 1000px) {
  .quiet-wrap {
    right: -12vw;
    width: min(62vw, 620px);
    opacity: var(--quiet-opacity);
  }

  .quiet {
    opacity: 0.72;
  }

  .hero-copy,
  .resources > * {
    max-width: 630px;
  }

  .hero-copy {
    padding-right: 8vw;
  }
}

@media (max-width: 720px) {
  .shell {
    width: min(100% - 34px, 1180px);
  }

  .topbar {
    height: 62px;
    padding-inline: 17px;
  }

  .status {
    display: none;
  }

  .quiet-wrap {
    z-index: 0;
    right: -26vw;
    bottom: -5vh;
    width: min(92vw, 590px);
    height: 92vh;
    opacity: var(--quiet-opacity);
  }

  .quiet {
    opacity: 0.38;
  }

  .hero {
    min-height: 100svh;
    padding-top: 88px;
  }

  .hero-frame {
    padding: 22px 18px 20px;
  }

  .hero-status {
    flex-direction: column;
  }

  .hero-status span {
    border-right: 0;
    border-bottom: 1px solid rgba(154, 160, 132, 0.14);
  }

  .hero-status span:last-child {
    border-bottom: 0;
  }

  .hero-copy {
    padding-right: 0;
  }

  h1 {
    font-size: clamp(3.1rem, 17vw, 5.2rem);
  }

  h1 .projects {
    letter-spacing: 0.19em;
  }

  .subhead {
    max-width: 92%;
  }

  .hero-actions {
    max-width: 310px;
  }

  .button {
    width: 100%;
  }

  .term {
    width: 100%;
    margin-top: 40px;
    padding: 15px 18px 17px;
  }

  .term-wide {
    margin-top: 0;
  }

  .resources {
    min-height: auto;
    padding-top: 95px;
    padding-bottom: 100px;
  }

  .section-code {
    display: none;
  }

  /* Index and badge share the top row; copy spans the full width beneath. */
  .project-card {
    grid-template-columns: 34px minmax(0, 1fr);
    gap: 12px 14px;
    padding: 18px 18px 20px;
  }

  .project-main {
    grid-column: 1 / -1;
  }

  .project-side {
    flex-direction: row;
    align-items: center;
    gap: 10px;
  }

  .footer {
    gap: 16px;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .quiet-wrap {
    transform: scale(var(--quiet-scale)) !important;
  }

  .button,
  .project-card,
  .quoteline,
  a {
    transition-duration: 0.001ms !important;
  }

  /* The automatic roll is skipped in script.js at this setting; the window
     stays scrollable by hand either way. */
  .term-dot {
    animation: none !important;
  }
}
