/* McGinn IEP Coaching — the whole design system.
   One stylesheet, four layers: tokens, base, components, utilities.
   No build step, no webfonts, no third-party requests, no JavaScript.
   Square corners are the signature; the only rounding is a focus ring. */

/* ============================================================
   1. TOKENS
   ============================================================ */

:root {
  /* surfaces */
  --paper:        #FFFFFF;
  --surface-alt:  #F4F4F4;
  --surface-inv:  #000000;

  /* ink */
  --ink:          #0A0A0A;
  --ink-strong:   #000000;
  --ink-soft:     #4A4A4A;
  --ink-inv:      #FFFFFF;
  --ink-inv-soft: #C9C9C9;

  /* lines */
  --hairline:     #C0C0C0;
  --rule:         #0A0A0A;
  --hairline-inv: #5A5A5A;

  /* the one non-monochrome value: a focus ring you cannot miss */
  --focus:        #0B57D0;

  /* type */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;

  --step--1: 0.9375rem;                                    /* 15px  meta */
  --step-0:  1.0625rem;                                    /* 17px  body */
  --step-1:  1.1875rem;                                    /* 19px  lead, post body */
  --step-2:  clamp(1.375rem, 1.10rem + 1.2vw, 1.75rem);    /* h3 */
  --step-3:  clamp(1.75rem,  1.30rem + 2.0vw, 2.5rem);     /* h2 */
  --step-4:  clamp(2.25rem,  1.50rem + 3.4vw, 3.75rem);    /* h1 */

  --lh-tight: 1.15;
  --lh-body:  1.6;
  --track-eyebrow: 0.14em;

  /* space — 4px base */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 72px;
  --section-y: clamp(48px, 8vw, 96px);

  /* structure */
  --measure:  66ch;
  --page-max: 1080px;
  --radius:   0;
  --border-w: 1px;
  --tap:      44px;
}

/* Monochrome means dark mode is a token flip, not a second design.
   One deliberate exception: the inverted bands (nav, contact, footer) go
   *darker* than the page rather than flipping to white. Someone who chose
   dark mode does not want a full-width white slab fired at them, and this
   audience includes people who chose it for light sensitivity. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:        #121212;
    --surface-alt:  #2A2A2A;
    --surface-inv:  #000000;
    --ink:          #EDEDED;
    --ink-strong:   #FFFFFF;
    --ink-soft:     #B0B0B0;
    --ink-inv:      #FFFFFF;
    --ink-inv-soft: #C0C0C0;
    --hairline:     #4A4A4A;
    --hairline-inv: #5A5A5A;
    --rule:         #EDEDED;
    --focus:        #8AB4F8;
  }
}

@media (prefers-contrast: more) {
  :root { --ink-soft: var(--ink); --hairline: var(--rule); --border-w: 2px; }
}

/* ============================================================
   2. BASE
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: var(--step-0)/var(--lh-body) var(--font-sans);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  color: var(--ink-strong);
  line-height: var(--lh-tight);
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin: 0 0 var(--s4);
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p, li { max-width: var(--measure); }
p { margin: 0 0 var(--s5); text-wrap: pretty; }
ul, ol { padding-left: var(--s5); }
li { margin-bottom: var(--s3); }

a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}
a:hover { text-decoration-thickness: 2px; }

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

hr {
  border: 0;
  border-top: var(--border-w) solid var(--hairline);
  margin: var(--s7) 0;
}

abbr[title] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
}

blockquote {
  margin: var(--s6) 0;
  padding-left: var(--s5);
  border-left: 3px solid var(--rule);
  font-size: var(--step-1);
}
blockquote p:last-child { margin-bottom: 0; }

strong { font-weight: 700; color: var(--ink-strong); }

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

/* #0B57D0 is 6.4:1 on white but only 3.3:1 on black, and the nav, hero
   button, contact band and footer are all black — which is most of the
   focusable elements on the site. The lighter blue is 10:1 there. */
.sitenav :focus-visible,
.band--inv :focus-visible,
.sitefoot :focus-visible { outline-color: #8AB4F8; }

.skip { position: absolute; left: -9999px; }
.skip:focus {
  position: fixed;
  left: var(--s4); top: var(--s4); z-index: 99;
  background: var(--surface-inv); color: var(--ink-inv);
  padding: var(--s3) var(--s5);
  text-decoration: none;
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   3. COMPONENTS
   ============================================================ */

/* ---- Layout shell ---- */

.wrap {
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 48px);
}

.band { padding-block: var(--section-y); }
.band--alt { background: var(--surface-alt); }
.band--inv { background: var(--surface-inv); color: var(--ink-inv); }
.band--inv h1, .band--inv h2, .band--inv h3 { color: var(--ink-inv); }
.band--inv a { color: var(--ink-inv); }
.band--line { border-top: var(--border-w) solid var(--hairline); }

/* ---- Nav. No JS, no hamburger: the links wrap to a second row. ---- */

.sitenav { background: var(--surface-inv); color: var(--ink-inv); }
.sitenav .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3) var(--s5);
  padding-block: var(--s3);
}
.nav-brand {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  color: var(--ink-inv);
  text-decoration: none;
  min-height: var(--tap);
  justify-content: center;
}
.nav-brand b {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.nav-brand span {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-inv-soft);
}
.nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  margin: 0; padding: 0;
  list-style: none;
}
.nav-links li { margin: 0; max-width: none; }
.nav-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-inv-soft);
  text-decoration: none;
}
.nav-links a:hover { color: var(--ink-inv); text-decoration: underline; }
.nav-links a[aria-current="page"] {
  color: var(--ink-inv);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.35em;
}

/* ---- Hero ---- */

/* The floor drops below ~400px so the phone CTA clears the fold on a small
   handset; above that the clamp is unchanged. */
.hero { padding-block: clamp(28px, 7vw, 80px) var(--section-y); }
.hero-grid {
  display: grid;
  gap: clamp(28px, 5vw, 56px);
  align-items: start;
}
@media (min-width: 60rem) {
  .hero-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }
}
.hero h1 { margin-bottom: var(--s5); }
.hero .lead { margin-bottom: var(--s6); }

/* Two stacked background layers. The photo sits on top; the placeholder
   sits underneath as a fallback. A background image that 404s fails
   silently, so swapping kevin-mcginn.jpg for a new headshot never risks a
   broken-image icon — worst case the placeholder shows through.
   (An <img> tag would not degrade this gracefully.) */
.portrait {
  aspect-ratio: 4 / 5;
  background-color: var(--surface-alt);
  background-image: url("/assets/kevin-mcginn.jpg"),
                    url("/assets/portrait-placeholder.svg");
  background-position: center top, center center;
  background-size: cover, cover;
  background-repeat: no-repeat, no-repeat;
  border: var(--border-w) solid var(--rule);
}
/* Below the 60rem breakpoint the portrait column inherits the full
   container width, which made it 1069px tall at 950px viewport and then
   snapped to 439px twenty pixels later. Cap it while stacked. */
.hero-grid > :last-child { max-width: 22rem; }
@media (min-width: 60rem) { .hero-grid > :last-child { max-width: none; } }

.portrait-caption {
  font-size: var(--step--1);
  color: var(--ink-soft);
  margin: var(--s3) 0 0;
  max-width: none;
}

/* ---- Buttons ---- */

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s4);
}
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: var(--s3) var(--s6);
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  font-size: var(--step-0);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
}
/* A phone number contains hyphens, and browsers treat those as legal break
   points — so on a 320px screen the primary CTA wrapped as "518-221-" /
   "4619". Keeping the number atomic means the label breaks between words
   instead, which is fine, while the number always reads as one thing. */
.nobr { white-space: nowrap; }

/* The underline on hover is what makes the state unambiguous in dark mode,
   where the background swap alone is subtle. */
.btn:hover { text-decoration: underline; text-underline-offset: 0.2em; }
.btn--solid { background: var(--surface-inv); color: var(--ink-inv); }
.btn--solid:hover { background: var(--surface-alt); color: var(--ink-strong); }
.btn--ghost { background: transparent; color: var(--ink-strong); }
.btn--ghost:hover { background: var(--surface-inv); color: var(--ink-inv); }
@media (prefers-color-scheme: dark) {
  .btn--solid { background: var(--ink-strong); color: var(--paper); border-color: var(--ink-strong); }
  .btn--solid:hover { background: transparent; color: var(--ink-strong); }
}
.band--inv .btn {
  border-color: var(--ink-inv);
  background: var(--ink-inv);
  color: var(--surface-inv);
}
.band--inv .btn:hover { background: transparent; color: var(--ink-inv); }

/* ---- Services: a ruled list, no cards, no icons ---- */

.services { list-style: none; margin: 0; padding: 0; counter-reset: svc; }
.services li {
  max-width: none;
  margin: 0;
  padding-block: var(--s5);
  border-top: var(--border-w) solid var(--hairline);
  display: grid;
  gap: var(--s2) var(--s5);
}
.services li:last-child { border-bottom: var(--border-w) solid var(--hairline); }
@media (min-width: 48rem) {
  .services li { grid-template-columns: 2.5rem minmax(0, 1fr); }
}
/* The teaser list on the home page is followed by a link to the full
   services page; without this the button sits flush against the last rule. */
.services + .actions { margin-top: var(--s6); }

.services .svc-num {
  counter-increment: svc;
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.services .svc-num::before { content: counter(svc, decimal-leading-zero); }
.services h3 { font-size: var(--step-1); margin: 0 0 var(--s2); }
.services p { margin: 0; }

/* ---- Credentials / résumé ---- */

.credentials { list-style: none; margin: 0; padding: 0; }
.credentials li {
  max-width: none;
  margin: 0 0 var(--s5);
  padding-left: var(--s5);
  border-left: 2px solid var(--rule);
}
.cred-role {
  display: block;
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--ink-strong);
}
.cred-meta {
  display: block;
  font-size: var(--step--1);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--s2);
}
.credentials p { margin: 0; }
/* The career entry runs to two paragraphs; without this they butt together. */
.credentials p + p { margin-top: var(--s3); }

/* ---- Stat row ---- */

.stats {
  display: grid;
  gap: var(--s5);
  list-style: none;
  margin: 0; padding: 0;
}
@media (min-width: 40rem) {
  .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.stats li {
  max-width: none;
  margin: 0;
  border-top: 3px solid var(--rule);
  padding-top: var(--s4);
}
.stats b {
  display: block;
  font-size: var(--step-2);
  line-height: 1.1;
  color: var(--ink-strong);
}
.stats span {
  display: block;
  font-size: var(--step--1);
  color: var(--ink-soft);
  margin-top: var(--s2);
}

/* .stats has no bottom margin so it can sit last in a section; when the
   credentials list follows it on the about page it needs the gap back. */
.stats + .credentials { margin-top: var(--s7); }

/* Divides the career entry from the dated highlights under it. Sized down
   from a normal h3 so it reads as a label inside the section, not as a
   competing heading. */
.cred-subhead {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: var(--s7) 0 var(--s5);
}

/* ---- "Are you feeling..." questions ---- */

/* Ruled rows rather than bullets: three short questions read as a checklist
   of symptoms, and a bullet glyph makes them look like a feature list. */
.asks { list-style: none; margin: 0 0 var(--s6); padding: 0; }
.asks li {
  max-width: none;
  margin: 0;
  padding-block: var(--s4);
  border-top: var(--border-w) solid var(--hairline);
  font-size: var(--step-1);
  color: var(--ink-strong);
}
.asks li:last-child { border-bottom: var(--border-w) solid var(--hairline); }

/* ---- Rate card ---- */

.rates { list-style: none; margin: 0 0 var(--s6); padding: 0; }
.rates li {
  max-width: none;
  margin: 0;
  padding-block: var(--s5);
  border-top: var(--border-w) solid var(--hairline);
  display: grid;
  gap: var(--s2) var(--s5);
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
}
.rates li:last-child { border-bottom: var(--border-w) solid var(--hairline); }
.rate-item {
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--ink-strong);
}
.rate-price {
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--ink-strong);
  text-align: right;
  font-variant-numeric: tabular-nums;
  /* the price is the scannable column; a price that wraps mid-figure ruins it */
  white-space: nowrap;
}
/* The explanation spans both columns so it starts under the label, not
   under a ragged gap left by the price. */
.rates p { grid-column: 1 / -1; margin: 0; max-width: var(--measure); color: var(--ink-soft); }

/* A subhead inside the rate card, sized down so it labels the explanation
   under the rates rather than competing with the section's own h2. */
.rates-sub {
  font-size: var(--step-1);
  margin: var(--s7) 0 var(--s4);
}

/* On a phone the label and the price fight over one line and the label
   wraps to three. One column reads better than a squeezed two. */
@media (max-width: 30rem) {
  .rates li { grid-template-columns: minmax(0, 1fr); }
  .rate-price { text-align: left; }
}

/* ---- Blog cards ---- */

.cards {
  display: grid;
  gap: var(--s5);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
}
.card {
  position: relative;
  border: var(--border-w) solid var(--hairline);
  padding: var(--s5);
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}
.card:hover { border-color: var(--rule); }
.card h3 { margin: 0; font-size: var(--step-2); text-wrap: pretty; }
.card h3 a { text-decoration: none; }
.card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.card h3 a:hover { text-decoration: underline; }
.card p { margin: 0; max-width: none; color: var(--ink); }
.card-meta {
  font-size: var(--step--1);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  margin: 0;
  max-width: none;
}
/* Scoped to .card so it outranks `.card p { margin: 0 }` and actually
   pins to the bottom, keeping the label aligned across a row of cards. */
.card .card-more {
  margin-top: auto;
  padding-top: var(--s2);
  font-size: var(--step--1);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
}

/* ---- Post body ---- */

.post { max-width: 68ch; }
.post-head { border-bottom: var(--border-w) solid var(--hairline); padding-bottom: var(--s6); margin-bottom: var(--s7); }
.post-meta {
  font-size: var(--step--1);
  color: var(--ink-soft);
  margin: 0;
  max-width: none;
}
.post-body { font-size: var(--step-1); }
.post-body h2 { font-size: var(--step-2); margin-top: var(--s8); }
.post-body h3 { font-size: var(--step-1); margin-top: var(--s7); }
.post-body h2:first-child, .post-body h3:first-child { margin-top: 0; }
.post-body ul, .post-body ol { margin-bottom: var(--s5); }
.post-nav {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: var(--border-w) solid var(--hairline);
}

/* A boxed aside — used for the "this is not legal advice" note. */
.note {
  border: var(--border-w) solid var(--hairline);
  background: var(--surface-alt);
  padding: var(--s5);
  font-size: var(--step-0);
  margin: var(--s6) 0;
}
.note p { margin: 0; max-width: none; }
.note p + p { margin-top: var(--s3); }

/* ---- Contact ---- */

.contact-list {
  list-style: none;
  margin: var(--s6) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s5);
}
@media (min-width: 60rem) {
  .contact-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.contact-list li { max-width: none; margin: 0; }
.contact-label {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-inv-soft);
  margin-bottom: var(--s2);
}
.contact-value {
  display: inline-flex;
  align-items: center;
  min-height: 56px;
  font-size: var(--step-2);
  font-weight: 700;
  color: var(--ink-inv);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  overflow-wrap: anywhere;
}
/* An email address is one unbreakable token, so at a fixed size it snaps
   mid-word on a narrow phone ("KevinAMcGinn@gmail." / "com"). Scaling it
   with the viewport keeps it on one line all the way down to 320px.
   The phone number is short enough to stay at full size. */
.contact-value--email { font-size: clamp(1.0625rem, 4.6vw, 1.75rem); }

/* ---- Footer ---- */

.sitefoot {
  background: var(--surface-inv);
  color: var(--ink-inv-soft);
  /* A hairline here is invisible black-on-black, which let the contact
     CTA dissolve into the legal boilerplate below it. */
  border-top: var(--border-w) solid var(--ink-inv-soft);
  padding-block: var(--s7);
  font-size: var(--step--1);
}
.sitefoot p { max-width: 70ch; margin: 0 0 var(--s4); }
.sitefoot p:last-child { margin-bottom: 0; }
.sitefoot strong { color: var(--ink-inv); }
.sitefoot a { color: var(--ink-inv); overflow-wrap: anywhere; padding-block: 7px; }
/* A phone number or address written into a sentence — on the 404 page, in a
   post — is still something people tap. Padding grows the hit area without
   boxing the link, which would stop a long address wrapping. The contact band
   and the buttons already carry a 56px target of their own. */
a[href^="tel:"]:not(.contact-value):not(.btn),
a[href^="mailto:"]:not(.contact-value):not(.btn) { padding-block: 7px; }
/* Padding on an inline link grows the hit area without boxing it, which would
   stop the long email wrapping; the looser leading keeps the lines clear. */
.sitefoot p:first-child { line-height: 2; }
.foot-rule {
  border: 0;
  border-top: var(--border-w) solid var(--hairline-inv);
  margin: var(--s5) 0;
}

/* ============================================================
   3b. SMALL SCREENS
   Most of the layout is fluid and needs no help. These are the few
   places where a phone-sized viewport produced a genuinely bad result.
   Tap targets stay at 44px throughout — only type and padding shrink.
   ============================================================ */

@media (max-width: 48rem) {
  /* Five nav items at full size wrap to two rows on every phone, which put
     the header back over 160px — a fifth of a small screen before any
     content. Tightening the type fits all five on one row down to 320px.
     Tap targets stay at 44px; only the type shrinks. */
  .sitenav .wrap { padding-block: var(--s2); }
  .nav-brand b { font-size: 1rem; }
  .nav-brand span { font-size: 0.6875rem; letter-spacing: 0.1em; }
  .nav-links { gap: 0 var(--s3); }
  .nav-links a { font-size: 0.75rem; letter-spacing: 0.06em; }
}

/* Below ~360px the five labels need 309px against 280px of usable width.
   Closing that gap would mean sub-12px type or 4px spacing, which is the
   wrong trade for an audience that includes low-vision readers — so the
   nav wraps to two rows on 320px-class phones and that is fine. */

@media (max-width: 30rem) {
  /* "Call or text 518-221-4619" wrapped mid-number in a shrink-to-fit
     button. Full-width buttons give the label the room to stay on one
     line, and stacked full-width targets are easier to hit one-handed. */
  /* Grid instead of flex column: grid items stretch, so the button's
     horizontal padding is never silently collapsed by flex shrinking. */
  .actions { display: grid; gap: var(--s3); }
  .actions .btn { width: 100%; }
}

.eyebrow {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 var(--s2);
  max-width: none;
}
.band--inv .eyebrow { color: var(--ink-inv-soft); }
.lead { font-size: var(--step-1); color: var(--ink); }
.fineprint { font-size: var(--step--1); color: var(--ink-soft); }
.measure { max-width: var(--measure); }
.stack > * + * { margin-top: var(--s5); }
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================
   5. PRINT — parents print the contact info to bring to a meeting
   ============================================================ */

@media print {
  :root {
    --paper: #FFF; --surface-alt: #FFF; --surface-inv: #FFF;
    --ink: #000; --ink-strong: #000; --ink-soft: #333;
    --ink-inv: #000; --ink-inv-soft: #333; --hairline: #999; --rule: #000;
  }
  body { font-size: 11pt; }
  /* .portrait is a CSS background image, and browsers drop backgrounds
     when printing — it printed as a full page of empty bordered box. */
  .sitenav, .skip, .card-more, .post-nav,
  .portrait, .portrait-caption, #services { display: none; }
  .band { padding-block: 12pt; }
  .band--inv, .sitefoot { border: 1px solid #000; }
  a { text-decoration: none; }
  .post-body a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }
  h1, h2, h3 { page-break-after: avoid; }
  p, li, blockquote { page-break-inside: avoid; }
}
