/* ethanwhipple.us — the whole stylesheet. No JavaScript on this site.

   The page is one building: a pale concrete wall (hero), an arched doorway
   into a dark room (projects), out through a curved threshold into light
   (Whiptronics, About), then down into a dark base (creed, footer).
   --arch-* sizes the doorway, --curve the two curved thresholds. */

@font-face {
  font-family: Inter;
  src: url(/assets/fonts/inter-latin.woff2) format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
/* Arial resized to Inter's metrics, so the swap does not move the layout. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107.12%;
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0%;
}

:root {
  --ink: #141414;
  --base: #0f0f0f;
  --room: #181818;
  --mid: #575755;   /* 4.9:1 on the darkest wall with the grain averaged in */
  --ash: #a8a8a6;
  --paper: #f5f5f3;
  --chalk: #e6e6e4;
  --gutter: clamp(16px, 4vw, 64px);
  --arch-w: 76vw;
  --arch-h: 30vw;
  --curve: clamp(36px, 9vw, 170px);
  --font: Inter, "Inter Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* Fine grain for the concrete. A procedural noise tile, not an image. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .09 0 0 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, p, ol, blockquote { margin: 0; }
ol { padding: 0; list-style: none; }
html { background: var(--base); -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  font: 400 1.125rem/1.6 var(--font);
  color: var(--ink);
  background: var(--chalk);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
p { text-wrap: pretty; }
/* break-word only splits a word that cannot fit on a line of its own: never
   at normal sizes, but at 200% text "Whiptronics" is wider than a phone. */
h1, h2, h3 { text-wrap: balance; overflow-wrap: break-word; }
a { color: inherit; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }
/* Pale text on a dark fill sitting on the pale wall: ring in ink instead. */
.btn-solid:focus-visible, .skip:focus-visible { outline-color: var(--ink); }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Read aloud, not shown: tells the three "Android app on Google Play" links
   apart. Absolute, so it takes no gap inside the flex pill. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.frame { max-width: 100rem; margin-inline: auto; }
.label { font-size: .75rem; font-weight: 600; letter-spacing: .26em; text-transform: uppercase; }
.wall { background: var(--grain), linear-gradient(172deg, #f6f6f4 0%, #e9e9e7 55%, #dededc 100%); }

.skip {
  position: absolute; left: var(--gutter); top: -6rem; z-index: 10;
  padding: .8rem 1.1rem; background: var(--ink); color: var(--paper);
  font-weight: 650; text-decoration: none;
}
.skip:focus { top: .75rem; }

/* Arrow for links that leave the site. Inter's subset here has no ↗. */
.ar {
  width: .7em; height: .7em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  transition: translate .3s cubic-bezier(.2, .7, .2, 1);
}
a:hover .ar { translate: 2px -2px; }

/* max-width + anywhere: at 200% text a domain name is wider than a phone. */
.btn, .pill {
  display: inline-flex; align-items: center; gap: .5em; max-width: 100%; overflow-wrap: anywhere;
  border-radius: 999px; font-weight: 650; text-decoration: none;
  transition: background-color .3s, box-shadow .3s, color .3s, translate .3s cubic-bezier(.2, .7, .2, 1);
}
.btn { min-height: 3.25rem; padding: .85rem 1.6rem; font-size: .9375rem; }
.btn-solid { background: var(--ink); color: var(--paper); box-shadow: 0 14px 30px -14px rgb(0 0 0 / .6); }
.btn-solid:hover { translate: 0 -2px; box-shadow: 0 20px 34px -14px rgb(0 0 0 / .6); }
.btn-soft { color: var(--ink); box-shadow: inset 0 0 0 1.5px #7f7f7d; }
.btn-soft:hover { background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--ink); }
.btn:active { translate: 0 0; }
.pill { min-height: 2.75rem; padding: .55rem 1.15rem; font-size: .9375rem; color: var(--paper); box-shadow: inset 0 0 0 1.5px #6e6e6c; }
.pill:hover { background: var(--paper); color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--paper); }
.pill-light { color: var(--ink); box-shadow: inset 0 0 0 1.5px #7f7f7d; }
.pill-light:hover { background: var(--ink); color: var(--paper); box-shadow: inset 0 0 0 1.5px var(--ink); }
.links { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.8rem; }

/* ---------------------------------------------------------------- HERO */
.hero { padding: 1.4rem var(--gutter) calc(var(--arch-h) + clamp(2rem, 5vw, 5rem)); }
.bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .25rem 2rem; }
.wordmark { font-size: 1.2rem; font-weight: 800; letter-spacing: -.015em; text-decoration: none; padding: .4rem 0; }
.bar nav { display: flex; flex-wrap: wrap; gap: 0 1.75rem; }
.bar nav a { color: var(--mid); text-decoration: none; padding: .55rem 0; }
.bar nav a:hover { color: var(--ink); }

.stage {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem;
  align-items: center; margin-top: clamp(2.5rem, 7vw, 7rem);
}
.copy { grid-column: 1 / 7; }
.copy .label { color: var(--mid); }
h1 {
  margin: 1.4rem 0 1.6rem;
  font-size: clamp(2.75rem, 6.2vw, 6.75rem); line-height: .98;
  font-weight: 760; letter-spacing: -.042em;
}
.sub { max-width: 36ch; color: #444; font-size: clamp(1.0625rem, 1.3vw, 1.25rem); }
.ctas { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2.1rem; }

/* Two arches and a sphere, lit from the upper left. */
.sculpt { grid-column: 7 / 13; position: relative; height: min(72svh, 42rem); min-height: 22rem; }
.sculpt i { position: absolute; display: block; }
.sculpt::after { content: ""; position: absolute; left: -6%; right: -2%; bottom: -1px; height: 1px; background: linear-gradient(90deg, transparent, #adadab 18%, #adadab 82%, transparent); }
.s-back {
  left: 2%; top: 11%; width: 54%; height: 89%;
  border-radius: 999px 999px 0 0;
  background: linear-gradient(100deg, #d0d0ce, #bdbdbb);
  box-shadow: 26px 34px 60px -26px rgb(0 0 0 / .45);
}
.s-front {
  right: 4%; top: 0; width: 52%; height: 100%;
  border-radius: 999px 999px 0 0;
  background: radial-gradient(130% 70% at 50% 0%, #fff 0%, #efefed 40%, #cdcdcb 100%);
  box-shadow: inset 26px 34px 46px -14px rgb(0 0 0 / .3), inset -2px 0 0 rgb(255 255 255 / .8);
}
.s-sphere {
  right: 16%; bottom: 0; width: 28%; aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff, #dcdcda 42%, #9d9d9b 100%);
  box-shadow: 22px 10px 30px -12px rgb(0 0 0 / .45);
}

/* ------------------------------------------------------------- PROJECTS */
/* The room's top is an arch standing in the hero wall: ::before is the
   lit reveal around the opening, ::after the dark opening itself. */
.room {
  position: relative; z-index: 1; display: flow-root;
  padding: 0 var(--gutter) calc(var(--curve) + clamp(2rem, 5vw, 5rem));
  background: var(--room); color: var(--paper);
  border-radius: 0 0 50% 50% / 0 0 var(--curve) var(--curve);
}
.room::before, .room::after {
  content: ""; position: absolute; bottom: 100%; left: 50%; translate: -50% 0;
  border-radius: 999px 999px 0 0; pointer-events: none;
}
/* The reveal: 14px of lit jamb, thinner on very narrow screens so it never
   reaches past the viewport edge. */
.room::before { --reveal: min(14px, 3.5vw); width: calc(var(--arch-w) + 2 * var(--reveal)); height: calc(var(--arch-h) + var(--reveal)); background: linear-gradient(90deg, #b0b0ae, #cfcfcd 60%, #bdbdbb); }
.room::after { width: var(--arch-w); height: var(--arch-h); background: linear-gradient(#111, var(--room)); }
.room-head {
  position: relative; z-index: 1; text-align: center;
  margin-top: calc(var(--arch-h) * -.62); padding-bottom: clamp(3rem, 7vw, 7rem);
}
.room-head .label, .room-note { color: var(--ash); }
.room-head h2 { margin-top: 1.1rem; font-size: clamp(2.5rem, 6.4vw, 7rem); line-height: .95; font-weight: 780; letter-spacing: -.045em; }
.room-note { margin-top: 1.25rem; font-size: 1rem; text-wrap: balance; }

.work {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; align-items: center;
  padding: 1.1rem 0 clamp(4rem, 8vw, 8rem); border-top: 1px solid #333;
}
.meta { grid-column: 1 / -1; display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 1.5rem; margin-bottom: clamp(2.5rem, 5vw, 5rem); color: var(--ash); }
.niche, .work-text { grid-row: 2; }
.work h3 { margin-bottom: 1.4rem; font-size: clamp(2.4rem, 5vw, 5.5rem); line-height: .92; font-weight: 780; letter-spacing: -.042em; }
.w1 h3 { font-size: clamp(2.75rem, 6.6vw, 7.5rem); }
.desc { max-width: 42ch; color: #cfcfcd; }

/* Each project gets a recess of its own shape and scale, lit from above.
   The number is cut into the back wall. */
.niche {
  position: relative; display: grid; place-items: center; overflow: hidden;
  background: radial-gradient(120% 90% at 50% 0%, #333, #1c1c1c 70%, #151515);
  box-shadow: inset 18px 26px 40px -10px rgb(0 0 0 / .9), inset -1px -1px 0 #3d3d3d;
}
.niche::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(75% 60% at 50% 0%, rgb(255 255 255 / .22), transparent 72%);
  opacity: .7; transition: opacity .7s;
}
.work:hover .niche::before, .work:focus-within .niche::before { opacity: 1; }
.niche span {
  position: relative; font-size: clamp(4rem, 9vw, 10rem); font-weight: 850; letter-spacing: -.06em;
  color: #232323; text-shadow: -1px -1px 0 #0a0a0a, 1px 1px 0 #474747;
}
.w1 .niche { grid-column: 1 / 6; aspect-ratio: 1; border-radius: 50%; }
.w1 .work-text { grid-column: 7 / 13; }
.w2 .work-text { grid-column: 1 / 7; }
.w2 .niche { grid-column: 8 / 12; aspect-ratio: 3 / 5; border-radius: 999px 999px 0 0; }
.w3 .niche { grid-column: 1 / 8; aspect-ratio: 2 / 1; border-radius: 999px 999px 0 0; }
.w3 .work-text { grid-column: 9 / 13; }
.w4 .work-text { grid-column: 1 / 7; }
.w4 .niche { grid-column: 9 / 13; aspect-ratio: 1; border-radius: 18%; }

/* ----------------------------------------------------------- WHIPTRONICS */
/* Starts under the room's curved bottom, so the dark room ends in a curve. */
.company { background: var(--grain), linear-gradient(#efefed, #dededc); }
/* Half the usual bottom padding: About's own top padding finishes the gap. */
.company { margin-top: calc(var(--curve) * -1); padding: calc(var(--curve) + clamp(5rem, 10vw, 10rem)) var(--gutter) clamp(2.5rem, 5vw, 5rem); }
.company-grid, .about-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; align-items: center; }
.bowl {
  grid-column: 2 / 6; aspect-ratio: 1; border-radius: 50%;
  display: grid; place-items: center;
  background: radial-gradient(circle at 60% 70%, #c9c9c7, #b0b0ae 70%);
  box-shadow:
    inset 30px 36px 50px -12px rgb(0 0 0 / .4), inset -2px -2px 0 rgb(255 255 255 / .7),
    0 0 0 22px #e2e2e0, 0 0 0 23px #c6c6c4;
}
.bowl img { width: 62%; height: auto; }
.company-text { grid-column: 7 / 12; }
.company-text .label { color: var(--mid); }
.company h2 { margin: 1rem 0 1.3rem; font-size: clamp(2.25rem, 4.4vw, 4.5rem); line-height: 1; font-weight: 760; letter-spacing: -.04em; }
.company-text > p:not(.label, .links) { max-width: 44ch; color: #3a3a3a; }

/* ----------------------------------------------------------------- ABOUT */
.about {
  padding: clamp(5rem, 10vw, 10rem) var(--gutter) calc(var(--curve) + clamp(5rem, 10vw, 10rem));
  background: var(--grain), linear-gradient(#dededc, #d2d2d0);
}
.about-grid { align-items: start; }
.about h2 { grid-column: 1 / 3; color: #4f4f4d; padding-top: .9em; }
.lead { grid-column: 3 / 11; font-size: clamp(1.75rem, 3.2vw, 3.25rem); line-height: 1.12; font-weight: 650; letter-spacing: -.025em; }
/* One column: two short paragraphs side by side came out four lines to two. */
.cols {
  grid-column: 3 / 11;
  margin-top: 2.5rem; padding-top: 1.4rem; border-top: 1px solid #b5b5b3; color: #2e2e2e;
}
.cols p { max-width: 62ch; }
.cols p + p { margin-top: 1em; }
.about .links { grid-column: 3 / 11; }
/* About's concrete is darker than the company wall: a darker outline keeps 3:1. */
.about .pill-light { box-shadow: inset 0 0 0 1.5px #6e6e6c; }
.about .pill-light:hover { box-shadow: inset 0 0 0 1.5px var(--ink); }

/* ----------------------------------------------------------------- CREED */
/* The base rises into the light with the same curve the room fell with.
   The three lines brighten as they go: light arriving, not decoration. */
.creed {
  position: relative; z-index: 1; margin-top: calc(var(--curve) * -1);
  padding: calc(var(--curve) + clamp(3.5rem, 8vw, 8rem)) var(--gutter) clamp(5rem, 9vw, 9rem);
  background: var(--base); color: var(--paper);
  border-radius: 50% 50% 0 0 / var(--curve) var(--curve) 0 0;
}
.creed h2 { color: #8f8f8d; }
.creed blockquote { margin: 2.4rem 0 0; font-size: clamp(2.1rem, 6vw, 6.75rem); line-height: .98; font-weight: 820; letter-spacing: -.045em; }
.creed blockquote span { display: block; }
.l1 { color: #727270; }
.l2 { color: #ababa9; }
.l3 { color: var(--paper); }

/* ---------------------------------------------------------------- FOOTER */
/* The name cut into the base like a foundation stone. Sized to the frame
   with container units; 7.82 is the set width of "ETHAN WHIPPLE" in em
   (measured 7.78 in Chrome, plus a hair). */
.base { padding: clamp(2rem, 5vw, 4rem) var(--gutter) 1.75rem; background: var(--base); color: var(--ash); }
.carve-box { container-type: inline-size; overflow: hidden; }
/* Generated content: the carving is decoration (WCAG 1.4.3 exempts it), and
   the name is already in the footer row below as real text. */
.carve::before { content: "Ethan Whipple"; }
.carve {
  margin: 0 0 clamp(1.5rem, 3vw, 3rem);
  font-size: calc(100cqi / 7.82); line-height: .78; font-weight: 900;
  letter-spacing: -.05em; text-transform: uppercase; white-space: nowrap;
  color: #171717; text-shadow: 0 -1px 0 #000, 0 1px 0 #2a2a2a;
}
.base-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 2rem; padding-top: 1.4rem; border-top: 1px solid #262626; font-size: .875rem; }
.base-row a { color: var(--paper); text-underline-offset: 3px; }
.base-row a:hover { text-decoration-thickness: 2px; }

/* --------------------------------------------------------------- MOTION */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  /* The sculpture assembles once on load. It is decoration, so starting
     invisible hides nothing a reader needs. */
  .sculpt i { animation: rise 1.1s cubic-bezier(.2, .7, .2, 1) both; }
  .s-front { animation-delay: .12s; }
  .s-sphere { animation-delay: .28s; }
  @keyframes rise { from { opacity: 0; translate: 0 28px; } }

  /* While the hero scrolls away, the sculpture sinks slower than the
     wall around it. Only where scroll timelines exist; nothing depends on it. */
  @supports (animation-timeline: scroll()) {
    .sculpt { animation: settle linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
    @keyframes settle { to { translate: 0 9vh; } }
  }
}

/* 404 page: the hero wall with nothing on it. */
.lost { min-height: 100svh; display: grid; align-items: center; padding-bottom: var(--gutter); }
.lost .label { color: var(--mid); }

/* --------------------------------------------------------------- MEDIUM */
/* Tablet widths: give every project text at least half the row. */
@media (max-width: 64em) {
  .w1 .niche { grid-column: 1 / 6; }
  .w1 .work-text, .w3 .work-text { grid-column: 7 / 13; }
  .w3 .niche { grid-column: 1 / 7; }
  .w2 .niche, .w4 .niche { grid-column: 8 / 13; }
}

/* ---------------------------------------------------------------- SMALL */
/* In em, so a reader's larger default text size also gets this layout. */
@media (max-width: 47.5em) {
  :root { --arch-w: 92vw; --arch-h: 46vw; }
  .stage, .work, .company-grid, .about-grid { display: block; }
  /* Kept short so the first project is not two screens down. */
  .sculpt { height: 64vw; min-height: 0; max-height: 30rem; margin-top: 3.5rem; }
  .meta { margin-bottom: 2.25rem; }
  .niche { width: 72%; margin: 0 auto 2.5rem; }
  .w2 .niche { width: 50%; }
  .w3 .niche { width: 100%; }
  .w4 .niche { width: 58%; }
  .bowl { width: min(76%, 22rem); margin: 22px auto 4.5rem; }
  .about h2 { padding-top: 0; margin-bottom: 1.25rem; }
  .base-row { flex-direction: column; }
}
