/* ============================================================
   Meryl Mathews — enhanced redesign
   Same palette, same gradient wash, same three contact links.
   The layout, the boxed portrait and the ornament take after
   resumeq.framer.website; the type is a hybrid lockup.
   ============================================================ */

:root {
  /* Brand. The hex and the channel list have to agree: every tint,
     shadow and ornament below is built from the -rgb triples rather
     than a literal, so moving a hue is a two-line edit and nothing is
     left behind in the old colour. */
  --brick:          #9f3146;
  --brick-rgb:      159, 49, 70;
  --brick-deep:     #520713;
  --brick-deep-rgb: 82, 7, 19;
  --brick-soft:     #C0674D;
  --brick-soft-rgb: 192, 103, 77;
  --brick-tint:     rgba(var(--brick-rgb), .08);

  /* Neutrals */
  --ink:          #241C19;
  --ink-soft:     #4A3E39;
  --muted:        #6E615B;
  --cream:        #FFFCFA;
  --wash-top:     #AFA3A1;
  --wash-mid:     #D5CDCB;
  --wash-bot:     #FFFFFF;

  /* The tint the cutout sits on. The headshot is a transparent PNG, so
     this shows through exactly where the background was removed, which
     is what "boxes it in". Mixed from --brick so it tracks the hue. */
  --panel-top:    color-mix(in srgb, var(--brick)  6%, var(--cream));
  --panel-tint:   color-mix(in srgb, var(--brick) 14%, var(--cream));
  --panel-bot:    color-mix(in srgb, var(--brick) 26%, var(--cream));

  /* Type — four roles
     --font         UI, labels, link pills (Poppins)
     --font-display the given name (Inter Display, self-hosted)
     --font-accent  the surname and the pill's aside (Instrument Serif)
     --font-serif   the bio (Source Serif 4) */
  --font:         "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display: "InterDisplay", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-accent:  "Instrument Serif", Georgia, "Times New Roman", Times, serif;
  --font-serif:   "Source Serif 4", Georgia, "Times New Roman", Times, serif;

  --wt-first: 250;

  /* Geometry */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 20px;
  --r-pill: 999px;
  --gutter: clamp(50px, 7vw, 250px);

  /* Portrait box. --fig-w is the frame's WIDTH; the height then follows
     from aspect-ratio: 4/5, so the rendered height is --fig-w * 1.25.
     With the multiplier at 0.8 that came back to --fig-h exactly, which
     is what the token name promises. At 0.98 it does not: the box renders
     1.225x taller than --fig-h says. Nothing is broken by that — the
     short-viewport rules still shrink it — but --fig-h is now a seed
     value, not the height. Put the multiplier back to 0.8 if you want
     height-driven sizing again. */
  --fig-h: clamp(340px, 46dvh, 470px);
  --fig-w: calc(var(--fig-h) * 0.98);

  /* Height reserved for the fixed contact bar on small screens. */
  --bar-h: 0px;

  /* Depth */
  --lift-1: 0 1px 2px rgba(36, 28, 25, .06), 0 6px 18px rgba(36, 28, 25, .07);
  --lift-2: 0 2px 4px rgba(36, 28, 25, .07), 0 18px 44px rgba(36, 28, 25, .13);
  --lift-fig: 0 6px 16px -6px rgba(var(--brick-rgb), .22),
              0 28px 56px -24px rgba(var(--brick-deep-rgb), .34);

  /* Motion */
  --ease: cubic-bezier(.22, .61, .36, 1);
  --fast: 160ms;
  --slow: 460ms;
}

/* Inter v4, SIL OFL 1.1. Subset to Latin, pinned to the Display optical
   size and converted to WOFF2; fonts/NOTICE.md records what changed and
   fonts/LICENSE.txt has to stay beside the file. */
@font-face {
  font-family: "InterDisplay";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/InterDisplay-latin.woff2") format("woff2");
}

/* ─── Reset ────────────────────────────────────────────────── */

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

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

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  color: var(--ink);
  background: var(--wash-bot);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { display: block; max-width: 100%; height: auto; }
ul  { list-style: none; margin: 0; padding: 0; }
a   { color: inherit; text-decoration: none; }

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

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--brick); color: #fff;
  padding: 10px 18px; border-radius: var(--r-pill);
  font-size: .875rem; font-weight: 500;
  transition: top var(--fast) var(--ease);
}
.skip-link:focus { top: 12px; }

.ico { width: 18px; height: 18px; flex: none; color: currentColor; }

/* ============================================================
   Hero
   ============================================================ */

.hero {
  flex: 1;
  position: relative;
  display: flex;
  overflow: hidden;
  padding-block: clamp(26px, 5vh, 56px);
  background:
    radial-gradient(120% 78% at 22% 0%, rgba(var(--brick-rgb), .12) 0%, transparent 62%),
    linear-gradient(180deg,
      var(--wash-top)  0%,
      var(--wash-mid) 34%,
      #EFEBE9 62%,
      var(--wash-bot) 90%);
}

.hero__inner {
  display: grid;
  /* The portrait column is a definite width derived from --fig-w, never
     content-sized: an auto track plus an image with max-width resolves
     to zero, which cost me an afternoon on the first build. */
  grid-template-columns: minmax(0, 1fr) var(--fig-w);
  /* Named areas rather than source order. Every block is a direct child,
     so reordering at a breakpoint is this one declaration and never a
     DOM change. The figure spans all five rows and centres itself. */
  grid-template-areas:
    "eyebrow figure"
    "name    figure"
    "role    figure"
    "bio     figure"
    "links   figure";
  align-content: center;
  column-gap: clamp(28px, 5vw, 78px);
  width: min(1180px, 100%);
  margin-inline: auto;
  padding-inline: var(--gutter);
  flex: 1;
  max-width: max(1280px, 77vw);
}

.hero__inner > * { min-width: 0; }

.eyebrow { grid-area: eyebrow; }
.name    { grid-area: name; }
.role    { grid-area: role; }
.bio     { grid-area: bio; }
.cc      { grid-area: links; }
.figure  { grid-area: figure; align-self: center; }

/* ============================================================
   Copy blocks
   ============================================================ */

/* — Eyebrow: rule plus letterspaced label — */
.eyebrow {
  display: flex; align-items: center; gap: 14px;
  margin: 0 0 clamp(14px, 2vh, 22px);
  font-size: .72rem; font-weight: 500;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--ink-soft);
}
.eyebrow::before {
  content: ""; width: 38px; height: 1px; flex: none;
  background: currentColor; opacity: .7;
}

/* — Name: two voices in one lockup — */
.name {
  margin: 0;
  line-height: .92;
  letter-spacing: -.035em;
  text-wrap: balance;
}
.name__first,
.name__last { display: inline-block; }

.name__first {
 /* font-family: var(--font-display);
  font-weight: var(--wt-first);
  font-size: clamp(2.7rem, 1.5rem + 3.9vw, 4.5rem);
  color: var(--ink-soft); */
  font-family: var(--font-accent);
    font-style: italic;
  font-weight: var(--wt-first);
    font-size: clamp(3.2rem, 1.7rem + 4.8vw, 5.5rem);
    letter-spacing: -.02em;
    color: var(--muted);
    margin-top: -.06em;
    /* The two words are inline-blocks, so the collapsed space between
       them is all that separates an italic l from an italic M. */
    margin-right: .08em;
}
.name__last {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 400;
  /* Instrument Serif runs small and tight for its point size, so it is
     set larger than the sans above it to look like the same lockup. */
  font-size: clamp(3.2rem, 1.7rem + 4.8vw, 5.5rem);
  letter-spacing: -.02em;
  color: var(--ink);
  margin-top: -.06em;
}

/* — Role pill — */
.role {
  display: inline-flex; align-items: center;
  /* Grid blockifies its items, so inline-flex alone no longer shrink-wraps;
     justify-self is what keeps the pill the width of its content. */
  justify-self: start;
  gap: clamp(10px, 1.4vw, 15px);
  max-width: 100%;
  margin: clamp(18px, 2.6vh, 28px) 0 0;
  padding: 9px clamp(16px, 1.8vw, 22px);
  border-radius: var(--r-pill);
  background: var(--brick-deep);
  color: #fff;
  box-shadow: 0 2px 10px rgba(var(--brick-deep-rgb), .26);
}
.role__dot {
  width: 9px; height: 9px; flex: none;
  border-radius: 50%;
  background: var(--brick-soft);
  box-shadow: 0 0 0 3px rgba(var(--brick-soft-rgb), .28);
}
.role__main {
  font-size: clamp(.92rem, .86rem + .24vw, 1.04rem);
  font-weight: 500; letter-spacing: -.005em;
  white-space: nowrap;
}
.role__rule {
  width: 1px; align-self: stretch; flex: none;
  margin-block: 2px;
  background: rgba(255, 255, 255, .3);
}
.role__aside {
  font-family: var(--font-accent);
  font-style: italic;
  font-size: clamp(.95rem, .88rem + .28vw, 1.1rem);
  color: rgba(255, 252, 250, .82);
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* — Bio — */
.bio {
  margin: clamp(18px, 2.6vh, 28px) 0 0;
  max-width: 58ch;
  /* Newlines come through as paragraph breaks; no markup is accepted. */
  white-space: pre-line;
  font-family: var(--font-serif);
  font-size: clamp(.92rem, .87rem + .22vw, 1.01rem);
  line-height: 1.72;
  color: var(--ink-soft);
}

/* — Contact card ────────────────────────────────────────────
   The engraved plate from the first design, carried over whole and
   set tighter vertically so it balances against the bio rather than
   competing with it. Structure and class names are unchanged, which
   is why the renderer and the admin panel needed no rework. */
.cc {
  margin-top: clamp(18px, 2.6vh, 28px);
  /* ch is measured in the card's own font (Poppins at 16px), not the
     bio's serif, so this is narrower than the bio's 58ch rather than
     wider as the numbers suggest. */
  max-width: 50ch;
  padding: 6px;                      /* the gap between the two rules */
  background: var(--cream);
  border: 1px solid var(--brick);
  border-radius: 4px;                /* print stock barely rounds */
  box-shadow: var(--lift-1);
}

.cc__plate {
  border: 1px solid rgba(var(--brick-rgb), .28);
  border-radius: 2px;
  padding: clamp(10px, 1.6vh, 15px) clamp(10px, 1.4vw, 15px) clamp(4px, .8vh, 8px);
}

.cc__eyebrow {
  display: flex; align-items: center; gap: 13px;
  margin: 0 0 clamp(8px, 1.2vh, 13px);
  font-size: .66rem; font-weight: 600;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--brick);
}
.cc__eyebrow::before,
.cc__eyebrow::after {
  content: ""; flex: 1; height: 1px;
  background: rgba(var(--brick-rgb), .3);
}

.cc__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* The renderer sets data-count rather than an inline grid-template, so
   the stack query below can still win. :where keeps these at class
   specificity so source order decides, not the attribute selector. */
.cc__row:where([data-count="1"]) { grid-template-columns: minmax(0, 1fr); }
.cc__row:where([data-count="2"]) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cc__row:where([data-count="4"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* The rule lives on the cell, not the link: an inset shadow on a
   rounded box follows its radius and bows at the ends. */
.cc__cell + .cc__cell { border-left: 1px solid rgba(var(--brick-rgb), .18); }

/* The vCard is the one action worth weighting, so its cell carries the
   tint. On the cell rather than the link so it reaches the hairlines;
   the link's own hover tint then layers over it. */
.cc__cell--emph {
  background: linear-gradient(180deg,
    rgba(var(--brick-rgb), .06) 0%, rgba(var(--brick-rgb), .13) 100%);
}
.cc__cell--emph .cc__label { color: var(--brick); }

.cc__item {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  height: 100%;
  padding: clamp(8px, 1.2vh, 12px) 8px clamp(9px, 1.4vh, 13px);
  border-radius: 2px;
  color: var(--ink-soft);
  text-align: center;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.cc__item .ico { color: var(--brick); width: 20px; height: 20px; }

.cc__text {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0; max-width: 100%;
}
.cc__label {
  font-size: clamp(.74rem, .7rem + .14vw, .8rem);
  font-weight: 500; letter-spacing: .06em; text-transform: uppercase;
}
.cc__value {
  font-size: clamp(.68rem, .65rem + .1vw, .72rem);
  color: var(--muted); letter-spacing: .01em;
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.cc__item:hover { background: var(--brick-tint); color: var(--brick); }
.cc__item:focus-visible { outline: 2px solid var(--brick); outline-offset: -2px; }

/* ============================================================
   Right column: the boxed portrait
   ============================================================ */

.figure {
  position: relative;
  width: var(--fig-w);
  justify-self: end;
  max-width: 100%;
}

/* Halftone, drawn with gradients rather than shipped as an SVG. The mask
   fades it out so it does not end on a hard edge. */
.figure__dots {
  position: absolute;
  top: 11px; left: calc(-1 * clamp(130px, 15vw, 210px));
  width: clamp(210px, 24vw, 310px);
  aspect-ratio: 1;
  background-image: radial-gradient(rgba(var(--brick-rgb), .45) 1.6px, transparent 1.7px);
  background-size: 16px 16px;
  -webkit-mask-image: radial-gradient(circle at 82% 72%, #000 4%, transparent 72%);
  mask-image: radial-gradient(circle at 82% 72%, #000 4%, transparent 72%);
  pointer-events: none;
}

.figure__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-lg);
  overflow: hidden;
  background:
    linear-gradient(170deg, var(--panel-top) 0%, var(--panel-tint) 52%, var(--panel-bot) 100%);
  box-shadow: var(--lift-fig);
}
.figure__frame picture { display: block; height: 100%; }
.figure__frame img {
  width: 100%; height: 100%;
  /* contain, not cover. Cover filled the frame edge to edge and the tint
     never showed, which is the whole point of the panel; contained and
     anchored to the bottom she sits in the box with the tint around her. */
  object-fit: contain;
  object-position: 50% 100%;
  padding-top: 7%;
}

.figure__chip {
  position: absolute;
  top: clamp(12px, 2vh, 20px);
  left: clamp(-26px, -2vw, -14px);
  z-index: 2;
  display: none; align-items: center; gap: 9px;
  margin: 0;
  padding: 8px 15px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .94);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--ink);
  font-size: .78rem; font-weight: 500; letter-spacing: .01em;
  white-space: nowrap;
  box-shadow: var(--lift-1);
}
.figure__chip::before {
  content: ""; width: 8px; height: 8px; flex: none;
  border-radius: 50%;
  background: var(--brick);
  box-shadow: 0 0 0 3px rgba(var(--brick-rgb), .2);
}

/* ============================================================
   Responsive
   ============================================================ */

/* The pill's two halves stop fitting side by side before the layout does. */
@media (max-width: 1080px) {
  :root { --fig-h: clamp(300px, 42dvh, 400px); }
  .bio { max-width: none; }
}

@media (max-width: 900px) {
  .role__rule, .role__aside { display: none; }
}

/* Stacked. The portrait moves between the role pill and the bio purely by
   rewriting the area list; the markup is untouched. The links leave the
   grid entirely and become a fixed bar, so they are not listed here. */
@media (max-width: 820px) {
  :root {
    --fig-h: clamp(300px, 40dvh, 380px);
    --bar-h: 168px;
  }

  .hero { padding-block: clamp(22px, 4vh, 40px); }
  .hero__inner {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "eyebrow"
      "name"
      "role"
      "figure"
      "bio"
      "links";
    /* The last row is a spacer the card comes to rest in. Padding will
       not do: padding sits outside the grid area, so a card spanning
       1/-1 would stop at the bio's edge and still cover its last lines. */
    grid-template-rows: repeat(5, auto) var(--bar-h);
    justify-items: center;
    row-gap: clamp(18px, 3vh, 30px);
    text-align: center;
  }

  /* The blocks carried their own top margins for the desktop stack; the
     grid's row-gap owns the rhythm here, so those would double up. */
  .name, .role, .bio { margin-top: 0; }
  .eyebrow { margin-bottom: 0; justify-content: center; }
  .role { justify-self: center; }
  .role__rule, .role__aside { display: revert; }
  .bio { margin-inline: auto; max-width: 62ch; }

  .figure { justify-self: center; }
  .figure__dots { left: -40px; top: -26px; }
  .figure__chip { left: 50%; transform: translateX(-50%); top: -14px; }

  /* Anchored to the bottom of the viewport while the hero scrolls, then
     parked above the footer rather than covering it.

     Sticky, not fixed, and the grid-area span is what makes it work: a
     sticky element can only travel inside its containing block, and for
     a grid item that block is its own grid area. Left in a single row of
     its own height there is nowhere to travel and sticky does nothing.
     Spanning every row gives it the height of the whole grid, so it
     pins to the viewport bottom and releases at the grid's bottom edge —
     which sits just above the footer. */
  .cc {
    grid-area: 1 / 1 / -1 / -1;
    align-self: end;
    position: sticky;
    /* A small offset so the pinned card reads as floating rather than
       welded to the edge; max() keeps it clear of a home indicator. */
    bottom: max(10px, env(safe-area-inset-bottom, 0px));
    z-index: 40;
    width: 100%;
    /* Pinned to the bottom it should span the column, so the desktop
       measure cap is lifted here. */
    max-width: none;
    margin-top: 0;
    box-shadow: var(--lift-2);
  }

  /* Sticky is dead inside a scroll container, and overflow: hidden makes
     one. `clip` does not, and unlike hidden it allows visible on the
     other axis, so the horizontal clipping the dots need survives. */
  .hero {
    overflow-x: clip;
    overflow-y: visible;
  }

  /* --bar-h has to be at least the card's rendered height or the resting
     position still clips into the bio. Measured max is 153px at 430px
     wide, where the longest label wraps; this leaves slack for a longer
     one. */

  /* Compact enough to pin: the detail line is what makes the card tall,
     and the label plus icon still say what each cell does. */
  .cc__value { display: none; }
  .cc__plate { padding-bottom: clamp(6px, 1vh, 10px); }
}

@media (max-width: 520px) {
  :root { --fig-h: min(56dvh, 360px); }
  /* The frame is sized from the viewport height, so on a short wide phone
     it can end up wider than the column and get clipped by .hero. */
  .figure { width: min(var(--fig-w), 100%); }
  /* On a phone the halftone has nowhere to sit but the screen edge, where
     it reads as a rendering artefact rather than ornament. */
  .figure__dots { display: none; }
  .role { flex-wrap: wrap; justify-content: center; row-gap: 2px; }
  .role__rule { display: none; }
  .link { flex: 1 1 auto; justify-content: center; }
}

/* The 95dvh band, same trade as the first design: a slice of the footer's
   accent shows on the first screen. Guarded on both axes because the hero
   clips its overflow, so anything past the cap would be unreachable. Here
   the content is ~650px against an 855px cap at 1440x900, so there is far
   more headroom than the first design had. */
@media (min-width: 821px) and (min-height: 800px) {
  .hero {
    /* Both bounds, not `height`: .hero is a flex item with flex: 1, and
       flex-basis beats height on the main axis. */
    min-height: 88dvh;
    max-height: 95dvh;
  }
}

/* Short desktop windows: the portrait yields before the copy does. */
@media (min-width: 821px) and (max-height: 760px) {
  :root { --fig-h: clamp(280px, 40dvh, 360px); }
  .bio { line-height: 1.6; }
}

/* ============================================================
   Entrance motion
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {
  .eyebrow, .name, .role, .bio, .cc, .figure {
    animation: rise var(--slow) var(--ease) both;
  }
  /* A transform on a sticky element re-anchors it mid-animation, so the
     pinned card would slide around as it enters. Fade it in instead. */
  @media (max-width: 820px) {
    .cc { animation-name: fade; }
  }
  @keyframes fade { from { opacity: 0; } to { opacity: 1; } }
  .eyebrow { animation-delay:  40ms; }
  .name    { animation-delay:  90ms; }
  .role    { animation-delay: 170ms; }
  .bio     { animation-delay: 230ms; }
  .cc      { animation-delay: 290ms; }
  .figure  { animation-delay: 130ms; }

  @keyframes rise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
  }
}

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

@media print {
  .hero { background: none; }
  .figure__dots, .figure__chip { display: none; }
}
