/* Handful Apps · shared stylesheet
   Visual language: "Modernist" from the Claude Design pass. Heavy display type,
   2px rules, zero radius, a red accent, and a full-bleed accent block for
   contact. Replaces the earlier "Industry" wireframe language.

   Self-contained on purpose: no webfonts, no CDN, no third-party request of any
   kind, because the site claims to load no trackers and that has to be literally
   true. The design system specifies Archivo from Google Fonts; that would break
   the promise, so this uses the system stack at heavy weights instead. */

:root {
  /* Modernist's #f3f2f2, lightened 30% toward white as requested. */
  --bg: #f7f6f6;
  --surface: #f0efef;
  --text: #201e1d;
  /* Solid muted values rather than opacity, so small text clears WCAG AA. */
  --muted: #56514f;
  --accent: #ec3013;       /* fills and large display type only */
  --accent-text: #c92507;  /* small text on light: 4.98:1 */
  --accent-deep: #dd2b0f;  /* contact block: white on it is 4.75:1 */
  --on-accent: #ffffff;
  --line: rgba(32, 30, 29, 0.4);
  --line-soft: rgba(32, 30, 29, 0.15);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1817;
    --surface: #232120;
    --text: #f3f2f2;
    --muted: #a8a3a1;
    --accent: #ff6a4d;
    --accent-text: #ff8265;
    --accent-deep: #c92507;
    --on-accent: #ffffff;
    --line: rgba(243, 242, 242, 0.35);
    --line-soft: rgba(243, 242, 242, 0.14);
  }
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
               Arial, sans-serif;
  font-size: 15px;
  line-height: 1.55;
  text-wrap: pretty;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-weight: 800; line-height: 1.05; letter-spacing: -0.03em; margin: 0 0 0.5rem; }
p { margin: 0 0 0.7rem; }

a { color: var(--accent-text); text-decoration: none; text-underline-offset: 3px; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
::selection { background: rgba(236, 48, 19, 0.25); }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

.wrap { max-width: 1200px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 64px); }
.rule2 { height: 2px; background: var(--line); border: 0; margin: 0; }

/* Kickers: the small uppercase accent labels */
/* One definition for every section label on the site. `.label` is the name the
   subpages use and `.kicker` the one the homepage uses; they are the same thing
   and must not drift apart. Any section rule that styles a bare `p` has to
   exclude these, or it wins on specificity and the label changes size. */
.kicker, .label {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  line-height: 1.4;
  color: var(--accent-text);
  margin: 0 0 24px;
}

/* Navigation */
.nav {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px clamp(20px, 5vw, 64px);
  border-bottom: 2px solid var(--line);
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-right: auto;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.brand svg { flex: none; display: block; }
.brand:hover { text-decoration: none; }
.nav a:not(.brand) {
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.nav a:not(.brand):hover { color: var(--accent-text); text-decoration: none; }

/* Hero */
.hero { padding: 72px 0 0; }
/* Subpage titles: real sentences, so they get a readable size. */
.hero h1 {
  font-size: clamp(30px, 4.6vw, 54px);
  line-height: 1.04;
  letter-spacing: -0.03em;
  margin: 0;
  max-width: 22ch;
}
/* The homepage hero, identified by the split row beneath it, gets the display
   size. Scoping this matters: the giant clamp on a subpage title renders a
   privacy policy heading at ~100px and it collides with the line under it. */
.hero:has(.hero-split) h1 {
  font-size: clamp(40px, 8vw, 108px);
  line-height: 0.96;
  letter-spacing: -0.035em;
  max-width: 16ch;
}
.hero h1 span { display: block; }
.hero h1 + .meta { margin-top: 16px; }
.hero-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 32px;
  padding: 32px 0 0;
  align-items: start;
}
.hero-lede { font-size: 17px; line-height: 1.55; max-width: 52ch; margin: 0; grid-column: span 2; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-start; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px 20px;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -0.01em;
  text-decoration: none;
  border: 2px solid var(--accent-deep);
  border-radius: 0;
  background: var(--accent-deep);
  color: var(--on-accent);
}
.btn:hover { text-decoration: none; filter: brightness(1.08); color: var(--on-accent); }
.btn-secondary {
  background: transparent;
  color: var(--text);
  border-color: var(--line);
}
.btn-secondary:hover { background: var(--surface); color: var(--text); filter: none; }

/* The three rules */
.rules {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 40px 32px;
  padding: 96px 0 0;
}
.rules .num {
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.04em;
  color: var(--accent-text);
  margin: 16px 0 20px;
  display: block;
}
.rules h2 { font-size: 24px; margin: 0 0 12px; letter-spacing: -0.02em; }
.rules p { font-size: 15px; line-height: 1.6; margin: 0; max-width: 34ch; color: var(--muted); }

/* Apps */
.apps-head { padding: 96px 0 0; }
.apps-head h2 {
  font-size: clamp(28px, 4vw, 52px);
  line-height: 1.02;
  margin: 0 0 24px;
  max-width: 20ch;
}
/* :not(.kicker) matters: `.apps-head p` is more specific than `.kicker`, so
   without it the section label loses its accent colour and renders grey. */
.apps-head p:not(.kicker) { font-size: 16px; line-height: 1.6; max-width: 52ch; margin: 0 0 40px; color: var(--muted); }

/* The apps index, set as a table. It stays readable as the list grows, which a
   card grid does not. */
.apps { width: 100%; border-collapse: collapse; font-size: 15px; }
.apps th {
  text-align: left;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
  padding: 0 8px 10px;
  border-bottom: 2px solid var(--line);
}
.apps td {
  padding: 22px 8px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.app-name { display: block; font-weight: 800; font-size: 19px; letter-spacing: -0.02em; }
.app-what { display: block; font-size: 14px; line-height: 1.5; color: var(--muted); margin-top: 2px; }
.apps .plat, .apps .stat { font-size: 14px; }
.apps .go a { font-weight: 800; font-size: 14px; letter-spacing: -0.01em; white-space: nowrap; }

/* Under this width four columns cannot be read, so each row becomes a block and
   the columns carry their own labels. The design only showed desktop. */
@media (max-width: 700px) {
  .apps thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .apps, .apps tbody, .apps tr, .apps td { display: block; width: 100%; }
  .apps tr { padding: 20px 0; border-bottom: 1px solid var(--line); }
  .apps tr:last-child { border-bottom: 0; }
  .apps td { border: 0; padding: 2px 0; }
  .apps td.plat::before { content: "Platforms: "; color: var(--muted); }
  .apps td.stat { margin-top: 4px; font-weight: 700; }
  .apps td.go { margin-top: 8px; }
}

/* About and long-form */
.about { padding: 96px 0 0; }
.about h2 { font-size: clamp(26px, 3.4vw, 42px); line-height: 1.03; margin: 0 0 28px; max-width: 20ch; }
.about p:not(.kicker) { font-size: 16px; line-height: 1.65; margin: 0 0 18px; max-width: 56ch; }
/* The h2 sits between the label and the first paragraph, so the opening line is
   not matched here and keeps full strength. Only the paragraphs after it mute. */
.about p + p { color: var(--muted); }

.prose { max-width: 68ch; }
.prose h2 { font-size: 22px; margin: 36px 0 10px; }
.prose h3 { font-size: 17px; margin: 26px 0 6px; }
.prose ul { padding-left: 1.2rem; }
.prose li { margin-bottom: 0.35rem; }
.prose .meta { font-size: 13px; color: var(--muted); }
.crumb { font-size: 13px; color: var(--muted); margin: 0 0 10px; }
.crumb a { color: var(--muted); }
.callout { padding: 20px 22px; margin: 22px 0; border-left: 4px solid var(--accent); background: var(--surface); }
.callout p:last-child { margin-bottom: 0; }
.pad { padding: 56px 0 0; }
.status {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
  white-space: nowrap;
}

/* Contact: the full-bleed accent block */
.contact {
  background: var(--accent-deep);
  color: var(--on-accent);
  margin-top: 96px;
}
.contact-inner { max-width: 1200px; margin: 0 auto; padding: clamp(48px, 8vw, 104px) clamp(20px, 5vw, 64px); }
.contact h2 {
  font-size: clamp(30px, 5.4vw, 72px);
  line-height: 0.98;
  letter-spacing: -0.035em;
  margin: 0;
  max-width: 18ch;
  color: var(--on-accent);
}
.contact h2 span { display: block; }
.contact p { font-size: 17px; line-height: 1.55; margin: 32px 0 0; max-width: 46ch; color: var(--on-accent); }
.contact-actions { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; margin-top: 40px; }
.contact-mail {
  display: inline-flex;
  align-items: center;
  background: var(--bg);
  color: var(--accent-text);
  font-weight: 800;
  font-size: 15px;
  padding: 14px 22px;
  text-decoration: none;
}
.contact-mail:hover { text-decoration: none; opacity: 0.9; color: var(--accent-text); }
.contact-link {
  font-weight: 800;
  font-size: 14px;
  color: var(--on-accent);
  border-bottom: 2px solid rgba(255, 255, 255, 0.55);
  padding-bottom: 2px;
  text-decoration: none;
}
.contact-link:hover { color: var(--on-accent); text-decoration: none; border-bottom-color: var(--on-accent); }
.contact :focus-visible { outline-color: var(--on-accent); }

/* App subpages keep the markup written for the previous language, so these map
   it onto this one. `.bp` (the old blueprint frame) is deliberately undefined:
   an unknown class simply does nothing, and this system has no corner marks. */
.frame { max-width: 1200px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 64px); }
.frame > .nav { max-width: none; margin: 0; padding-left: 0; padding-right: 0; }
.frame > .foot { padding-left: 0; padding-right: 0; }
.hero .lede {
  font-size: 17px;
  line-height: 1.55;
  max-width: 56ch;
  color: var(--muted);
  margin: 20px 0 10px;
}
.hero h1 + .lede, .crumb + h1 { margin-top: 20px; }
.rule { border-top: 2px solid var(--line); margin-top: 44px; }
.foot-note { font-size: 13px; color: var(--muted); }

/* Footer */
.foot {
  display: flex;
  gap: 12px 32px;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  padding: 32px 0 56px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--muted);
}
.foot-links { display: flex; gap: 24px; flex-wrap: wrap; }
.foot-links a { color: var(--text); text-decoration: none; }
.foot-links a:hover { color: var(--accent-text); }

@media (max-width: 640px) {
  .hero { padding-top: 48px; }
  .rules, .apps-head { padding-top: 64px; }
  .app { padding: 24px; }
  .app-tile { width: 88px; height: 88px; }
  .app-tile svg { width: 48px; height: 48px; }
  .contact { margin-top: 64px; }
}

/* Tables inside prose. The apps index above has its own rules, scoped to
   .apps, so a table written in a page body had no styling at all and rendered
   as cramped unbordered text. The user guide sets 10 of them and the privacy
   policy 1. Same tokens as .apps, lighter, since these carry reference
   material rather than the hub's main navigation. */
.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
  margin: 20px 0 28px;
}
.prose th {
  text-align: left;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
  padding: 0 10px 8px 0;
  border-bottom: 2px solid var(--line);
}
.prose td {
  padding: 11px 10px 11px 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
  line-height: 1.5;
}
.prose th:last-child, .prose td:last-child { padding-right: 0; }
.prose td code { font-size: 13px; }

/* Below this the 2 and 3 column reference tables stop fitting, so each row
   becomes a block. Headers are dropped rather than repeated per cell: unlike
   the apps index these tables are read top to bottom, and the first cell in
   each row already says what the row is about. */
@media (max-width: 620px) {
  .prose table, .prose tbody, .prose tr, .prose td { display: block; width: 100%; }
  .prose thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .prose tr { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
  .prose td { border: 0; padding: 2px 0; }
  .prose td:first-child { font-weight: 700; }
}

/* Email addresses are split at render time so the literal string never appears in
   the served HTML. .eml-x holds decoy text that is hidden from the page, from text
   selection and from assistive technology, so a scraper that strips the tags
   harvests an address that cannot be delivered. span.eml outranks .contact-mail's
   inline-flex so the no-JS fallback text is not split into flex items. */
span.eml { display: inline; }
.eml-x { display: none; }


/* App screenshots. A real class, replacing the inline flex the Says Who page used,
   so every app overview page lays out the same way and the row wraps on a phone. */
.shots {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.shots figure { margin: 0; flex: 1 1 200px; max-width: 260px; }
.shots img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line-soft);
  border-radius: 16px;
}
.shots figcaption {
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 10px;
}

/* The current page is marked in the nav rather than removed from it. Removing it is
   what let every page grow a different nav; this keeps one shape everywhere. */
.nav a:not(.brand)[aria-current="page"] { color: var(--accent-text); }

/* Status badges now actually differ. Every badge was rendering the same grey because
   only `.status` had a rule, while README documented three states. */
.status.live { color: var(--accent-text); }
.status.dev  { color: var(--muted); }
.status.next { color: var(--muted); }
