/* 12think.ai -- one stylesheet for the one page.
   Tokens and base first, then the page top to bottom, then the responsive
   overrides and reduced motion. */

:root {
  color-scheme: dark;
  --ink: #07070a;
  --white: #ffffff;
  --body: #a6afb8;
  --muted: #7d8994;
  --blue-light: #87aed5;
  --blue-deep: #255b91;
  --yellow: #ffed29;
  --yellow-hover: #e6d525;
  --hairline: #202428;
  --nav-link: #c5cbd1;
  --ink-raised: #222326;
  --placeholder: #67737d;
  --diagram-ink: #e8e6df;
  --drawing-fill: #13171c;

  /* Ink at low alpha: the hairline and the field border inside the gold slab,
     where every grey in the system washes out. */
  --on-gold: #353532;
  --on-gold-dim: #4a4a45;
  --on-gold-rule: rgba(7, 7, 10, .16);
  --on-gold-edge: rgba(7, 7, 10, .3);
  --on-gold-error: #8c1d0f;

  --display: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --body-font: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* The bio grid, mobile first: one column under 640px, portrait beside the
     prose above it. */
  --cols-bio: 1fr;
  --gap-bio: 32px;
}

/* 880, not 640: the bio's left column is 240px wide, so splitting any earlier
   squeezed the prose to a 37-44 character measure across the whole tablet
   band. Stacked, the prose gets the section's full width (capped at 640px by
   .bio__prose), which reads correctly all the way down to a phone. */
@media (min-width: 880px) {
  :root { --cols-bio: 240px minmax(0, 1fr); }
}
@media (min-width: 1024px) {
  :root { --gap-bio: 64px; }
}

/* Self-hosted rather than fetched from fonts.googleapis.com: the whole
   typographic identity of this page rests on these two faces, and a
   third-party stylesheet in front of them blocks first paint and reflows the
   hero headline on swap. Latin subset, variable, preloaded in the document
   head -- 67KB for both.

   Both faces are SIL Open Font License 1.1, reproduced in OFL.txt beside
   them. Keep that file next to the woff2s if either is ever moved. */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url("ibm-plex-sans-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: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("plus-jakarta-sans-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;
}

* { box-sizing: border-box; }

/* The contact form toggles .form, .form-success and #contact-prompt through
   the hidden attribute, and all three carry display:flex from a class rule.
   Author declarations beat the UA stylesheet's [hidden] { display: none }
   whatever their specificity, so without this the confirmation panel renders
   on load and the form never hides after a send. !important is the point:
   it has to outrank any display a component sets on itself. */
[hidden] { display: none !important; }

html {
  background: var(--ink);
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--white);
  font-family: var(--body-font);
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

h1, h2 { font-family: var(--display); text-wrap: balance; }
h1 { margin: 0; }

::selection { background: var(--yellow); color: var(--ink); }

a { color: inherit; text-underline-offset: .25em; }

/* :focus carries the ring for browsers that do not know :focus-visible; the
   :not() rule hands control back wherever :focus-visible is understood. */
a:focus,
a:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 5px;
}

a:focus:not(:focus-visible) { outline: none; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 10;
  padding: 10px 14px;
  background: var(--yellow);
  color: var(--ink);
  transform: translateY(-150%);
}

.skip-link:focus { transform: translateY(0); }

/* Every section is inset to the same content width, so the side gutters are
   always bare ink -- which is what lets the pinned header get away without a
   full-bleed backdrop. */
.site-header,
.hero,
.pillars,
.about,
.close,
.site-footer {
  width: min(100% - 48px, 1180px);
  margin-inline: auto;
}

/* ---------------------------------------------------------------
   Header, pinned
   z-index stays under the skip-link's 10 so that still surfaces on focus.
   --------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 9;
  min-height: 96px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--ink);
  border-bottom: 1px solid var(--hairline);
}

/* The in-page nav links would land under the pinned header without this. */
#work,
#about,
#contact { scroll-margin-top: 112px; }

.brand { display: inline-flex; padding-block: 6px; }
.brand img { display: block; width: 126px; height: auto; }
.brand--muted { opacity: .48; }

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(22px, 3vw, 40px);
}

.site-nav a {
  padding-block: 14px;
  color: var(--nav-link);
  font-size: 14px;
  letter-spacing: .01em;
  text-decoration: none;
}

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

/* ---------------------------------------------------------------
   Hero -- a deep blue slab against the near-black page, inset to the
   content width so its edges line up with every section below.
   The promise is the only thing on the slab, so the slab takes a floor
   height and centres it.
   --------------------------------------------------------------- */
.hero {
  display: flex;
  align-items: center;
  min-height: clamp(250px, 32vh, 360px);
  /* The bottom margin lifts the section rule below off the slab's edge, so it
     reads as the next section starting rather than the slab's own underline. */
  margin-block: clamp(30px, 4vw, 48px) clamp(44px, 6vw, 80px);
  padding: clamp(48px, 6vw, 80px) clamp(26px, 4vw, 56px);
  background: var(--blue-deep);
}

.hero__title {
  max-width: 22ch;
  margin: 0;
  font-weight: 700;
  font-size: clamp(36px, 7vw, 64px);
  line-height: 1.15;
  letter-spacing: -.02em;
}

/* ---------------------------------------------------------------
   Buttons
   --------------------------------------------------------------- */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  min-height: 52px;
  padding: 0 25px;
  background: var(--yellow);
  color: var(--ink);
  border-radius: 2px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color .2s ease;
}

.button:hover { background: var(--yellow-hover); }

/* The arrow travels on hover. Transform rather than the old `gap` change:
   gap is a layout property, so animating it relaid out the button every frame. */
.button svg {
  width: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  transition: transform .25s cubic-bezier(.16, 1, .3, 1);
}

.button:hover svg { transform: translateX(5px); }
.button__label--short { display: none; }

/* Yellow is the page's marker colour, so on the gold slab the buttons invert
   to ink. */
.button--dark { background: var(--ink); color: var(--white); }
.button--dark:hover { background: var(--ink-raised); }

/* The submit is a <button>, which brings its own borders and font. */
button.button {
  border: 0;
  cursor: pointer;
  font-family: var(--body-font);
  font-size: 15px;
}

/* ---------------------------------------------------------------
   Sections on the ink field
   --------------------------------------------------------------- */
.pillars,
.about {
  border-top: 1px solid var(--hairline);
  padding-block: clamp(60px, 8vw, 90px);
}

/* ---------------------------------------------------------------
   Offerings
   --------------------------------------------------------------- */
.pillar-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(32px, 4vw, 56px);
  align-items: start;
}

/* Hairline gutters. The grid gap sits to the left of the rule and the padding
   to its right, so each column's text clears the hairline by the same amount
   on both sides. */
.pillar + .pillar {
  padding-left: clamp(32px, 4vw, 56px);
  border-left: 1px solid var(--hairline);
}

.pillar__art {
  display: block;
  width: 100%;
  max-width: 260px;
  height: auto;
  margin: 0 0 clamp(20px, 2vw, 28px);
}

.pillar__title {
  margin: 0 0 14px;
  color: var(--white);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(20px, 1.9vw, 24px);
  line-height: 1.2;
  letter-spacing: -.01em;
  text-wrap: balance;
}

.pillar__body {
  max-width: 44ch;
  margin: 0;
  color: var(--body);
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: .005em;
}

/* Hand-drawn diagrams: an ink line for structure, one yellow marker per
   drawing, and scratchy hatching inside a solid face -- inverted from the
   pen-and-ink reference so the hatch reads as highlight on the near-black
   canvas. */
.pl-ink,
.pl-mark {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Ink draws the structure; yellow annotates exactly one idea per drawing.
   Keeping that split is what makes the three read as one hand. */
.pl-ink { stroke: var(--diagram-ink); stroke-width: 2.4; }
.pl-mark { stroke: var(--yellow); stroke-width: 2.6; }

/* Pattern only, no colour, so it composes with either stroke above. Dashes
   mean provisional throughout: the prototype frame, and the fractional role. */
.pl-dash { stroke-dasharray: 10 8; }

/* The sprinting figure sits inside the arrow it shares a colour with, so it
   needs the extra weight to separate at the rendered size. */
.pl-figure { stroke-width: 3.4; }

.pl-node { fill: var(--diagram-ink); stroke: none; }
.pl-face { fill: var(--drawing-fill); }

.pl-hatch {
  fill: none;
  stroke: var(--diagram-ink);
  stroke-width: 1.1;
  stroke-linecap: round;
  opacity: .45;
}

/* ---------------------------------------------------------------
   Bio
   The portrait is the system's one circular shape. The hairline ring ties it
   back to the flat, bordered vocabulary used everywhere else.
   --------------------------------------------------------------- */
.bio-grid {
  display: grid;
  grid-template-columns: var(--cols-bio);
  gap: var(--gap-bio);
  align-items: start;
}

/* The portrait carried the left column alone, which left a lone circle
   floating beside five paragraphs and a third of the section empty. The name
   and role join it, so the two columns carry comparable weight. */
.bio__who { max-width: 240px; }

.bio__portrait {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  display: block;
  object-fit: cover;
}

.bio__name {
  margin: 22px 0 6px;
  color: var(--white);
  font-family: var(--display);
  font-weight: 700;
  /* Sized to sit on one line inside the 240px column. */
  font-size: clamp(24px, 2.2vw, 28px);
  line-height: 1.1;
  letter-spacing: -.01em;
}

.bio__title {
  margin: 0 0 24px;
  color: var(--blue-light);
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.3;
}

.bio__prose {
  max-width: 640px;
  margin: 0;
  color: var(--body);
  font-size: 17px;
  line-height: 1.65;
}

.bio__prose + .bio__prose { margin-top: 18px; }

/* ---------------------------------------------------------------
   Close
   One gold slab holds the whole thing: the heading and a single-line
   description across the top, then the call, the "or" and the note heading on
   one line, with the form below the note. Inside the slab the colour roles
   invert -- ink carries the type, the buttons and the focus rings, and the
   input fill is bounded by an ink border rather than by contrast.
   --------------------------------------------------------------- */
.close {
  margin-block: clamp(44px, 6vw, 80px) clamp(30px, 4vw, 48px);
  padding: clamp(44px, 6vw, 72px) clamp(28px, 4vw, 64px) clamp(48px, 6vw, 76px);
  background: var(--yellow);
  color: var(--ink);
}

.close__title {
  max-width: 18ch;
  margin: 0 0 16px;
  color: var(--ink);
  font-weight: 700;
  font-size: clamp(30px, 3.8vw, 46px);
  line-height: 1.06;
  letter-spacing: -.02em;
}

/* Across the full slab width, so it sets as one line on a wide screen. */
.close__lede {
  margin: 0;
  color: var(--on-gold);
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.55;
  text-wrap: pretty;
}

/* Three columns whose first row is the height of the button, with each item
   centred in it, so the button, the "or" and the note heading read as one
   line. The form then spans all three columns rather than sitting under the
   heading in column three -- that left a tall empty block of slab beside it,
   and left the form's edge aligned to nothing. Spanning puts it flush with the
   button, the lede and the section heading. */
.close__split {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  grid-template-areas:
    "book or   lede"
    "form form form";
  gap: 0 clamp(20px, 2.6vw, 40px);
  align-items: start;
  margin-top: clamp(32px, 4vw, 48px);
  padding-top: clamp(30px, 4vw, 44px);
  border-top: 1px solid var(--on-gold-rule);
}

.close__book { grid-area: book; align-self: start; }
.close__or { grid-area: or; }
.close__formlede { grid-area: lede; }

/* Both share the one area: they never coexist, and a display:none grid item
   takes no space, so the row leaves no gap behind the hidden one. Capped so
   the paired fields do not stretch across the whole slab. */
.form,
.form-success { grid-area: form; max-width: 760px; }

/* min-height matches .button, so these sit on the button's centre line rather
   than on its top edge. */
.close__or,
.close__formlede {
  display: flex;
  align-items: center;
  min-height: 52px;
  margin: 0;
}

.close__or {
  justify-content: center;
  color: var(--on-gold);
  font-size: 17px;
}

.close__formlede {
  color: var(--ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(18px, 1.8vw, 22px);
  line-height: 1.25;
}

/* A yellow focus ring on gold is 1:1 -- invisible. Ink reads 16.67:1 here. */
.close a:focus,
.close a:focus-visible { outline-color: var(--ink); }
.close .button--dark:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------------------------------------------------------------
   Contact form
   An ink hairline frames it as one object on the slab.
   --------------------------------------------------------------- */
.form,
.form-success {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: clamp(16px, 2vw, 22px);
  padding: clamp(20px, 2.4vw, 28px);
  border: 1px solid var(--on-gold-edge);
  text-align: left;
}

.form-success { gap: 10px; }
.form-success:focus { outline: none; }

/* Intrinsic, so it responds to the width the form actually has rather than to
   the viewport. The old 640px query fired while the form itself was still in a
   narrow column, which cramped the pairs between 900 and 1100px. */
.form__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 18px;
}

.field { display: flex; flex-direction: column; gap: 7px; }

.field__label {
  color: var(--ink);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.field__note {
  color: var(--on-gold-dim);
  text-transform: none;
  letter-spacing: 0;
}

.field input,
.field select,
.field textarea {
  font-family: var(--body-font);
  /* 16px: anything smaller triggers iOS auto-zoom on focus */
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  color-scheme: light;
  background: var(--white);
  /* White on gold is 1.13:1, so the border draws the boundary, not the fill. */
  border: 1px solid var(--ink);
  border-radius: 2px;
  padding: 12px 14px;
  width: 100%;
}

.field textarea { resize: vertical; min-height: 118px; }
.field input::placeholder,
.field textarea::placeholder { color: var(--placeholder); }  /* 4.86:1 on the white fill */

.field input:hover,
.field select:hover,
.field textarea:hover { border-color: var(--on-gold-dim); }

/* At offset 1px an ink ring sits flush against the field's own ink border and
   the two merge into one thick line. The gold showing through at 3px is what
   makes the focused state legible, and the inset shadow doubles the border
   without the reflow a border-width change would cause. */
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  box-shadow: inset 0 0 0 1px var(--ink);
}

/* The form is a flex column, so without this the submit stretches full width */
.form .button { align-self: flex-start; }

/* Post-submit states */
.form-success__title {
  margin: 0;
  color: var(--ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
}

.form-success__body { margin: 0; color: var(--on-gold); font-size: 15px; }
.form-success__body a { color: var(--ink); text-decoration: underline; }

.form-error {
  margin: 0;
  padding-left: 14px;
  border-left: 2px solid var(--on-gold-error);
  color: var(--on-gold-error);
  font-size: 14px;
}

.form-error a { color: var(--ink); text-decoration: underline; }

/* Spam honeypot: hidden from people, tempting to bots */
.form__gotcha {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------------------------------------------------------------
   Footer
   --------------------------------------------------------------- */
.site-footer {
  min-height: 138px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: .01em;
}

.site-footer p { margin: 0; }

/* ---------------------------------------------------------------
   Responsive
   --------------------------------------------------------------- */
@media (max-width: 900px) {
  .pillar-grid { grid-template-columns: 1fr; gap: clamp(36px, 6vw, 48px); }
  .pillar + .pillar {
    padding-left: 0;
    padding-top: clamp(36px, 6vw, 48px);
    border-left: 0;
    border-top: 1px solid var(--hairline);
  }
  .pillar__art { margin-inline: auto; }

  /* The areas string above declares three columns, so stacking needs both
     the columns and the areas restated. */
  .close__split {
    grid-template-columns: 1fr;
    grid-template-areas: "book" "or" "lede" "form";
    row-gap: clamp(10px, 2vw, 16px);
  }
  .close__or { min-height: 0; justify-content: flex-start; margin-top: 6px; }
  .close__formlede { min-height: 0; margin-top: 10px; }
}

@media (max-width: 620px) {
  .site-header,
  .hero,
  .pillars,
  .about,
  .site-footer { width: min(100% - 32px, 1180px); }

  .site-header { min-height: 76px; }
  #work,
  #about,
  #contact { scroll-margin-top: 92px; }

  /* The gold slab goes edge to edge on a phone rather than keeping a gutter
     it cannot spare. */
  .close { width: 100%; }
  .close__book { width: 100%; }
  .close__or { justify-content: center; }
  .form .button { align-self: stretch; }

  .button__label--full { display: none; }
  .button__label--short { display: inline; }

  .site-footer { min-height: 110px; }
}

/* Not a blanket kill. The only motion on the page is the hovered arrow and
   the smooth scroll, so those two go; the button's colour change is feedback
   rather than motion and is deliberately kept. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .button svg { transition: none; }
  .button:hover svg { transform: none; }
}
