/* MudmanTim's Apps -- shared design system
   Software showroom, not a portfolio. Dark shell, per-app accent colors,
   system fonts only, subtle motion. See the visual-polish plan for the
   full rationale. */

:root {
  --bg: #0b0d12;
  --bg-elevated: #14171f;
  --bg-elevated-2: #1b1f29;
  --line: #262b36;
  --text: #f3f4f6;
  --text-muted: #9aa1ad;
  /* Lightened from #6b7280 (~3.96:1) to meet WCAG AA (>=4.5:1) on --bg while
     staying visibly quieter than --text-muted. Used for eyebrows, captions,
     install notes, and the copyright. */
  --text-faint: #828b99;

  /* Keyboard focus ring — one bright, accent-neutral colour that reads on the
     dark shell and on every per-app accent. */
  --focus: #8ea2ff;

  --radius: 18px;
  --radius-sm: 12px;
  --content-width: 1080px;
  --prose-width: 720px;

  --streakfit-a: #ff8a3d;
  --streakfit-b: #39d353;
  --ppg: #00ff41;
  --promptsurgeon: #ef4444;
  --porchlight: #e0a458;
  --porchlight-deep: #8a5a2b;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
}

html, body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

img { max-width: 100%; display: block; }

/* ---------- accessibility: focus + skip link ---------- */

/* One consistent, visible keyboard-focus ring across the whole site. Mouse
   users never see it (:focus-visible); keyboard users always do. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 6px;
}
/* Don't leave a stray ring on mouse click for browsers that support :focus-visible. */
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute;
  left: 12px;
  top: -48px;
  z-index: 100;
  background: var(--text);
  color: var(--bg);
  font-size: 13px;
  font-weight: 700;
  padding: 10px 16px;
  border-radius: 999px;
  text-decoration: none;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  transition: top 0.15s ease;
}
.skip-link:focus-visible { top: 12px; outline-offset: 2px; }

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

/* ---------- layout shell ---------- */

.shell {
  flex: 1;
  width: 100%;
}

.wrap {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: 0 24px;
}

.prose-wrap {
  max-width: var(--prose-width);
  margin: 0 auto;
  padding: 0 24px;
}

header.site-header {
  padding: 24px 0;
}

header.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 8px;
  text-decoration: none;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.01em;
}

.brand .brand-mark { color: var(--text); }
.brand .brand-sep { color: var(--text-faint); font-weight: 400; }

nav.site-nav a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 600;
  margin-left: 20px;
  transition: color 0.15s ease;
}

nav.site-nav a:hover { color: var(--text); }

/* Marks the current product in the nav / footer so people know where they are. */
nav.site-nav a[aria-current="page"] { color: var(--text); }
.footer-links a[aria-current="page"] { color: var(--text); }

/* Mobile: four long product names can't share the header row with the brand
   without wrapping into a jumble. Below the grid breakpoint the header is
   brand-only — every product is one scroll away as a card, and the footer
   carries the full set. */
@media (max-width: 639px) {
  nav.site-nav { display: none; }
  header.site-header { padding: 18px 0; }
}

/* ---------- hero ---------- */

.hero {
  padding: 56px 0 48px;
  text-align: center;
}

.eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 14px;
}

.hero h1 {
  font-size: clamp(32px, 5vw, 52px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.08;
  margin: 0 0 18px;
}

.hero p.lede {
  font-size: 17px;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 560px;
  margin: 0 auto;
}

/* ---------- Today's Nonsense (daily teaser) ----------
   A living module directly under the hero: it changes every day, giving
   returning visitors a fresh reason to come back. Hidden by default and
   revealed by JS only once the day's document has actually loaded (fails
   gracefully to nothing). The institution palette tints the card at runtime;
   these rules cover everything else, matching the shared dark shell. */

.today-nonsense-wrap {
  padding: 4px 0 44px;
}

.today-card {
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  padding: 26px 30px 28px;
  overflow: hidden;
  transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.today-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 42px rgba(0, 0, 0, 0.4);
}

.today-card:active { transform: translateY(-1px); }

.today-card .eyebrow {
  margin: 0 0 14px;
}

.dn-institution {
  font-size: clamp(21px, 3.4vw, 30px);
  font-weight: 800;
  letter-spacing: 0.005em;
  line-height: 1.14;
  text-transform: uppercase;
  margin: 0 0 6px;
}

.dn-format {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 16px;
}

.dn-body {
  font-size: clamp(17px, 2.1vw, 21px);
  line-height: 1.5;
  color: var(--text);
  margin: 0 0 20px;
  max-width: 660px;
}

.today-card .cta {
  color: var(--text);
}

.today-card:hover .cta,
.today-card:focus-visible .cta {
  transform: translateX(3px);
}

/* Rare-item flag — only rendered when the day's item is rare (data-rare). */
.dn-rare {
  display: none;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  background: rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 3px 10px;
  margin: 0 0 14px;
}

#today-nonsense[data-rare="true"] .dn-rare {
  display: inline-flex;
}

@media (prefers-reduced-motion: reduce) {
  .today-card { transition: none; }
  .today-card:hover { transform: none; }
  .today-card:hover .cta,
  .today-card:focus-visible .cta { transform: none; }
}

/* ---------- product grid + cards ---------- */

.grid-products {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  padding: 8px 0 64px;
}

@media (min-width: 640px) {
  .grid-products { grid-template-columns: 1fr 1fr; }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  background: var(--bg-elevated);
  transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
  transform: translateY(-4px);
}

.card:active { transform: translateY(-1px); }

.card-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 2 / 1;
  overflow: hidden;
}

.card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 20px 22px 22px;
  gap: 6px;
}

.card-status {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
  margin-bottom: 6px;
}

.status-dot { width: 6px; height: 6px; border-radius: 50%; }

.status-live { color: #6ee894; background: rgba(110, 232, 148, 0.12); }
.status-live .status-dot { background: #6ee894; }

.status-dev { color: #fbbf24; background: rgba(251, 191, 36, 0.12); }
.status-dev .status-dot { background: #fbbf24; }

.status-invite { color: #e0a458; background: rgba(224, 164, 88, 0.14); }
.status-invite .status-dot { background: #e0a458; }

/* Paused — a deliberately quiet, neutral badge for archived work. It must not
   read as an active/available status, so it uses the faint slate, not an
   accent colour. */
.status-paused { color: var(--text-faint); background: rgba(154, 161, 173, 0.12); }
.status-paused .status-dot { background: var(--text-faint); }

.card h2 {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
}

.card p.tagline {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 0 0 6px;
  flex: 1;
}

.card .cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  font-size: 13px;
  font-weight: 700;
  padding: 2px 0;
  transition: transform 0.2s ease;
}

/* Small delight: the "→" nudges forward when the card is hovered or focused. */
.card:hover .cta,
.card:focus-visible .cta { transform: translateX(3px); }

/* per-app accents */
.accent-streakfit .card-banner { background: linear-gradient(135deg, var(--streakfit-a), var(--streakfit-b)); }
.accent-streakfit .cta { color: var(--streakfit-b); }
.card.accent-streakfit:hover { border-color: var(--streakfit-b); box-shadow: 0 14px 36px rgba(57, 211, 83, 0.18); }

.accent-ppg .card-banner { background: #05130a; }
.accent-ppg .cta { color: var(--ppg); }
.card.accent-ppg:hover { border-color: var(--ppg); box-shadow: 0 14px 36px rgba(0, 255, 65, 0.16); }

.accent-promptsurgeon .card-banner { background: #17070a; }
.accent-promptsurgeon .cta { color: var(--promptsurgeon); }
.card.accent-promptsurgeon:hover { border-color: var(--promptsurgeon); box-shadow: 0 14px 36px rgba(239, 68, 68, 0.18); }

.accent-porchlight .card-banner { background: linear-gradient(135deg, var(--porchlight-deep), var(--porchlight)); }
.accent-porchlight .cta { color: var(--porchlight); }
.card.accent-porchlight:hover { border-color: var(--porchlight); box-shadow: 0 14px 36px rgba(224, 164, 88, 0.2); }

/* ---------- section: why / install ---------- */

section.op-section {
  padding: 56px 0;
  border-top: 1px solid var(--line);
}

section.op-section h2.section-title {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 8px;
  text-align: center;
}

section.op-section p.section-sub {
  text-align: center;
  color: var(--text-muted);
  font-size: 15px;
  max-width: 520px;
  margin: 0 auto 36px;
}

.value-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 640px) {
  .value-grid { grid-template-columns: repeat(4, 1fr); }
}

.value-item {
  text-align: center;
  padding: 0 8px;
}

.value-item .value-icon {
  font-size: 22px;
  margin-bottom: 10px;
}

.value-item h3 {
  font-size: 14px;
  font-weight: 700;
  margin: 0 0 6px;
}

.value-item p {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 0;
}

.install-steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  max-width: 640px;
  margin: 0 auto;
}

@media (min-width: 640px) {
  .install-steps { grid-template-columns: 1fr 1fr; }
}

.install-card {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 20px;
}

.install-card h3 {
  font-size: 14px;
  font-weight: 700;
  margin: 0 0 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.install-card ol {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--text-muted);
}

.install-note {
  text-align: center;
  font-size: 12px;
  color: var(--text-faint);
  max-width: 480px;
  margin: 20px auto 0;
}

/* ---------- footer ---------- */

footer.site-footer {
  border-top: 1px solid var(--line);
  padding: 32px 0;
}

footer.site-footer .wrap {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: center;
  text-align: center;
}

footer.site-footer .footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  justify-content: center;
}

footer.site-footer .footer-links a {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
}

footer.site-footer .footer-links a:hover { color: var(--text); }

footer.site-footer .copyright {
  font-size: 12px;
  color: var(--text-faint);
}

/* ---------- landing pages ---------- */

.page-hero {
  padding: 48px 0 8px;
}

.page-hero .eyebrow { text-align: left; margin: 0 0 10px; }

.page-hero h1 {
  font-size: clamp(30px, 4.4vw, 44px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0 0 16px;
}

.page-hero p.lede {
  font-size: 16px;
  line-height: 1.65;
  color: var(--text-muted);
  max-width: 560px;
  margin: 0 0 24px;
}

.page-hero .status-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 22px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  color: #0b0d12;
  background: var(--text);
  border: none;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.15s ease;
}

.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35); }
.btn-primary:active { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .btn-primary, .card .cta { transition: none; }
  .btn-primary:hover { transform: none; }
  .card:hover .cta, .card:focus-visible .cta { transform: none; }
}

.btn-primary.on-streakfit { background: linear-gradient(90deg, var(--streakfit-a), var(--streakfit-b)); color: #0b0d12; }
.btn-primary.on-ppg { background: var(--ppg); }
.btn-primary.on-porchlight { background: var(--porchlight); }

.hero-visual {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin: 32px 0 8px;
  background: var(--bg-elevated);
}

.hero-visual img { width: 100%; height: auto; display: block; }

.mobile-shot {
  max-width: 260px;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-elevated);
}

.mobile-shot img { width: 100%; height: auto; display: block; }

.proof-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  flex-wrap: wrap;
}

.proof-row .mobile-shot { flex: 0 0 auto; max-width: 200px; }

.proof-row .proof-copy { flex: 1 1 240px; min-width: 220px; }

.proof-row .proof-copy h3 {
  font-size: 16px;
  font-weight: 800;
  margin: 0 0 6px;
}

.proof-row .proof-copy p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

.feature-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}

@media (min-width: 640px) {
  .feature-grid { grid-template-columns: 1fr 1fr; }
}

.feature-item {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 20px;
}

.feature-item h3 {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 6px;
}

.feature-item p {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

.status-callout {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-left: 3px solid var(--text-faint);
  border-radius: var(--radius-sm);
  padding: 20px 22px;
  margin: 8px 0 32px;
}

.status-callout.on-promptsurgeon { border-left-color: var(--promptsurgeon); }
.status-callout.on-porchlight { border-left-color: var(--porchlight); }

.status-callout h3 {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0 0 8px;
}

.status-callout p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0 0 8px;
}

.status-callout p:last-child { margin-bottom: 0; }

.page-close {
  text-align: center;
  padding: 48px 0 64px;
  border-top: 1px solid var(--line);
  margin-top: 48px;
}

.page-close p.close-line {
  font-size: 16px;
  color: var(--text-muted);
  margin: 0 0 16px;
}

.page-close .cta {
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
}

/* Per-page accent for the closing "Back to MudmanTim's Apps" link — replaces
   the inline style="color: var(--…)" that was repeated on every landing page. */
body[data-page="streakfit"] .page-close .cta { color: var(--streakfit-b); }
body[data-page="password-generator-pro"] .page-close .cta { color: var(--ppg); }
body[data-page="prompt-surgeon"] .page-close .cta { color: var(--promptsurgeon); }
body[data-page="porchlight"] .page-close .cta { color: var(--porchlight); }
body[data-page="porchlight-beta"] .page-close .cta { color: var(--porchlight); }

/* Shared caption under a screenshot / recreated-UI visual. Was an inline
   style="text-align:center;font-size:12px;color:var(--text-faint)…" repeated
   per page (and a near-duplicate .pl-proof-caption on PorchLight). */
.media-caption {
  text-align: center;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-faint);
  margin: 10px auto 0;
  max-width: 460px;
}

/* ---------- Daily Nonsense: neutral fallback ----------
   The homepage teaser is progressive enhancement. The neutral fallback card
   (#dn-fallback) is what renders with no JS, while today's document loads, and
   whenever the feed is unavailable/slow/malformed/empty. It never fabricates a
   daily item — it is a truthful, evergreen link to the publication. JS swaps in
   the specific item (#dn-card) only once a usable one has actually arrived. */

/* Robust hide: an author rule on .today-card/.card would otherwise beat the UA
   [hidden] rule (author beats UA regardless of specificity), leaving a
   "hidden" card visible. Force it. */
[hidden] { display: none !important; }

.dn-fallback-body {
  font-size: clamp(16px, 2vw, 19px);
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0 0 20px;
  max-width: 660px;
}

/* ---------- archive (paused / preserved work) ----------
   Archived projects are intentionally NOT product cards: they are non-interactive
   record entries. No banner, no link, no CTA button — so they can never be
   mistaken for something available to use. */

.archive-grid {
  list-style: none;
  margin: 0;
  padding: 8px 0 48px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}

@media (min-width: 640px) {
  .archive-grid { grid-template-columns: 1fr 1fr; }
}

.archive-item {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 24px 24px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.archive-item h2 {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 4px 0 2px;
}

.archive-item .tagline {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

body[data-page="archive"] .page-close .cta { color: var(--focus); }

/* Understated footer route to the archive. Quieter than the product links so it
   never competes with active products. */
.footer-meta {
  display: flex;
  justify-content: center;
}

.footer-meta a {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  text-decoration: none;
  transition: color 0.15s ease;
}

.footer-meta a:hover { color: var(--text-muted); }

/* ---------- reveal-on-scroll (subtle) ---------- */

.reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .card:hover { transform: none; }
}
