/* ==========================================================================
   david-sanker.com — quadrant hero (design v2)
   --------------------------------------------------------------------------
   One square. Four sub-squares. A single continuous portrait running beneath
   all four, so the divisions read as how the world sorts him while the image
   underneath stays one person. The motto sits on the crosshair.

   Two rules this layout depends on:

   1. The background image belongs to the SQUARE, not to each cell. Four cells
      each with their own background-image would break the illusion the whole
      design rests on.
   2. Cell labels live in the square's OUTER corners, so the centre stays clear
      for the motto at every viewport. That is what makes it survive on a
      390px phone without stacking or hiding anything.

   Loaded in addition to main.css, which supplies the tokens and fonts.
   ========================================================================== */

/* ---------- Page shell ---------- */

/* This page is a single non-scrolling composition. The body becomes the flex
   column so anything rendered above .quad-page (the scaffold banner today, a
   future notice bar) is subtracted from the space the square gets, instead of
   silently pushing the bottom bar past the fold. */
body:has(.quad-page) {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* main.css sets the light paper background; this page is dark edge to edge,
     and without this a strip of paper shows below the bottom bar. */
  background: var(--ink);
}

/* base.html wraps every page in <main id="main">, so .quad-page is a grandchild
   of body, not a child. Without passing the flex growth through <main> the
   square sits at the top of the viewport with the leftover space dumped below
   it, instead of being centred in the frame. */
body:has(.quad-page) > main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ---------- Square shell ---------- */

.quad-stage {
  /* The square is as large as the space left over allows, and never larger, so
     it is always whole — never cropped, never scrolled past.

     Sized explicitly, NOT by `flex + aspect-ratio`: every child here is
     absolutely positioned, so the stage has no intrinsic size, `flex-basis:
     auto` resolves to 0 and aspect-ratio then derives 0 height from 0 width —
     the square vanishes. --chrome is the measured height of the bars above and
     below plus gaps; it is verified against the real render, not guessed. */
  --square: min(100vw, calc(100dvh - var(--chrome)));
  --chrome: 11.5rem;
  width: var(--square);
  height: var(--square);
  flex: 0 0 auto;
  margin-inline: auto;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--ink);
}

.quad-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  /* Slightly muted at rest so type stays readable; a hovered cell restores
     its own region to full presence (see .quad-cell:hover). */
  filter: saturate(0.72) contrast(1.04);
  transition: filter 420ms ease;
}

/* Marks the placeholder so it cannot ship unnoticed. */
.quad-stage[data-placeholder='true'] .quad-bg {
  outline: 3px dashed var(--signal);
  outline-offset: -3px;
}

/* Readability scrim. Darkest at the four outer corners where the labels sit,
   and at the centre behind the motto — the two places type lands. */
.quad-stage::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 50%, rgba(10, 11, 13, 0.62) 0%,
                    rgba(10, 11, 13, 0.30) 26%, rgba(10, 11, 13, 0) 46%),
    linear-gradient(to bottom, rgba(10, 11, 13, 0.55) 0%,
                    rgba(10, 11, 13, 0.12) 32%, rgba(10, 11, 13, 0.12) 68%,
                    rgba(10, 11, 13, 0.60) 100%);
}

/* ---------- The four cells ---------- */

.quad-grid {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
}

.quad-cell {
  position: relative;
  display: flex;
  padding: clamp(0.85rem, 3.2vmin, 2.5rem);
  text-decoration: none;
  color: #f4f5f1;
  transition: background-color 320ms ease;
}

/* Labels sit in the square's outer corners, leaving the centre for the motto. */
.quad-cell[data-pos='top-left']     { align-items: flex-start; justify-content: flex-start; text-align: left; }
.quad-cell[data-pos='top-right']    { align-items: flex-start; justify-content: flex-end;   text-align: right; }
.quad-cell[data-pos='bottom-left']  { align-items: flex-end;   justify-content: flex-start; text-align: left; }
.quad-cell[data-pos='bottom-right'] { align-items: flex-end;   justify-content: flex-end;   text-align: right; }

.quad-cell:hover,
.quad-cell:focus-visible {
  background-color: color-mix(in srgb, var(--cell-accent) 26%, transparent);
}

.quad-cell:focus-visible {
  outline: 2px solid #f4f5f1;
  outline-offset: -6px;
}

/* Hovering one cell lifts the whole photo — the person is one thing, so the
   image responds as a whole rather than lighting up a quarter of itself. */
.quad-stage:has(.quad-cell:hover) .quad-bg,
.quad-stage:has(.quad-cell:focus-visible) .quad-bg {
  filter: saturate(1) contrast(1.08);
}

/* 22ch keeps lines readable on a wide screen; 100% stops a long brand name
   ("The Road Not Taken") from spilling across the centre line on a phone. */
.quad-label { max-width: min(22ch, 100%); }

/* The three parts stack. They are spans (a link may not contain block-level
   flow content in valid HTML), so the stacking is done here, not by tag. */
.quad-name, .quad-line, .quad-note { display: block; }

.quad-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-stretch: 112%;
  font-size: clamp(0.95rem, 3.1vmin, 1.9rem);
  line-height: 1.06;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.quad-line {
  font-family: var(--font-mono);
  font-size: clamp(0.5rem, 1.42vmin, 0.78rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-top: 0.5em;
  color: var(--cell-accent);
  /* The accent colours are mid-tone on their own; a light mix keeps them
     legible against the photo without losing brand identity. */
  color: color-mix(in srgb, var(--cell-accent) 45%, #ffffff);
}

/* The one-line description is detail, not navigation — it would crowd a phone
   screen, so it appears only where there is room for it. */
.quad-note {
  display: none;
  font-size: 0.9rem;
  line-height: 1.4;
  margin-top: 0.7em;
  color: rgba(244, 245, 241, 0.74);
  max-width: 26ch;
}

/* Hairlines between the quadrants. Drawn over the cells, ignoring pointers, so
   they never interrupt a tap target. */
.quad-rules {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}
.quad-rules::before,
.quad-rules::after {
  content: '';
  position: absolute;
  background: rgba(244, 245, 241, 0.30);
}
.quad-rules::before { left: 50%; top: 0; bottom: 0; width: 1px; transform: translateX(-0.5px); }
.quad-rules::after  { top: 50%; left: 0; right: 0; height: 1px; transform: translateY(-0.5px); }

/* ---------- Motto on the crosshair ---------- */

.quad-motto {
  position: absolute;
  z-index: 4;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(78%, 30ch);
  text-align: center;
  pointer-events: none;
  color: #f7f8f4;
  font-family: var(--font-body);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(0.82rem, 2.75vmin, 1.65rem);
  line-height: 1.32;
  text-wrap: balance;
  text-shadow: 0 1px 24px rgba(10, 11, 13, 0.75);
}

/* ---------- Chrome above and below the square ---------- */

.quad-page {
  /* dvh, not vh: on iOS Safari the address bar makes vh taller than what is
     actually visible, which would push the bottom bar off-screen. */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(0.5rem, 1.6vh, 1.25rem);
  padding-block: clamp(0.5rem, 1.6vh, 1.25rem);
  background: var(--ink);
  overflow: hidden;
}

/* Bars span the page rather than tracking the square's edges. The square is
   sized by flex against the remaining height, so its width is not knowable in
   CSS without a circular dependency — matching it would need a ResizeObserver,
   which is not worth a script for pure alignment. */
.quad-bar {
  width: 100%;
  flex: 0 0 auto;
  padding-inline: clamp(1rem, 4vw, 3rem);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  color: rgba(244, 245, 241, 0.82);
}

.quad-bar a { color: inherit; text-decoration: none; }
.quad-bar a:hover { color: #fff; opacity: 1; }

.quad-bar .label { color: rgba(244, 245, 241, 0.55); }

.quad-wordmark {
  font-family: var(--font-mono);
  font-size: clamp(0.62rem, 1.5vmin, 0.78rem);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.quad-nav {
  display: flex;
  gap: clamp(0.6rem, 2vmin, 1.4rem);
  font-family: var(--font-mono);
  font-size: clamp(0.56rem, 1.35vmin, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ---------- Wider screens ---------- */

@media (min-width: 48rem) {
  .quad-note { display: block; }
}

/* Landscape phones: vertical space is the scarce resource. The bars do not get
   proportionally shorter, so the offset stays large here — measured against a
   844x390 render, where 5rem left the bottom bar below the fold. */
@media (max-height: 30rem) {
  .quad-stage { --chrome: 9.5rem; }
}

/* ---------- Load sequence ---------- */
/* The rules draw out from the centre, then the labels arrive. One moment,
   matching the idea: the divisions appear on top of a person already there. */

@media (prefers-reduced-motion: no-preference) {
  .quad-rules::before { animation: draw-v 620ms cubic-bezier(0.22, 0.61, 0.36, 1) 120ms both; }
  .quad-rules::after  { animation: draw-h 620ms cubic-bezier(0.22, 0.61, 0.36, 1) 120ms both; }

  .quad-label {
    opacity: 0;
    animation: settle 500ms ease forwards;
    animation-delay: calc(var(--i, 0) * 90ms + 620ms);
  }

  .quad-motto {
    opacity: 0;
    animation: settle 700ms ease forwards 980ms;
  }
}

@keyframes draw-v { from { transform: translateX(-0.5px) scaleY(0); } to { transform: translateX(-0.5px) scaleY(1); } }
@keyframes draw-h { from { transform: translateY(-0.5px) scaleX(0); } to { transform: translateY(-0.5px) scaleX(1); } }
@keyframes settle { to { opacity: 1; } }
