/* ==========================================================================
   MOONLIT ICE — Stylesheet
   Plain CSS, no build step. Organized in sections:
   1. Reset & base
   2. Typography
   3. Persistent navigation (wordmark, tabs, toggle)
   4. Overlay menu
   5. Homepage
   6. Editorial page (asymmetric archive + lightbox)
   7. Commission page (grid) + individual project page
   8. Information page
   9. Responsive (mobile) adjustments
   ========================================================================== */

/* -----------------------------
   1. Reset & base
   ----------------------------- */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  background: #ffffff;
  color: #000000;
  font-family: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
  background: none;
  border: none;
  cursor: pointer;
  color: inherit;
}

ul {
  list-style: none;
}

/* -----------------------------
   2. Typography
   ----------------------------- */
.wordmark {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.nav-tab {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.nav-tab.is-active {
  font-style: italic;
}

/* -----------------------------
   3. Persistent navigation
   ----------------------------- */
.site-nav {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 100;
}

.site-nav a,
.site-nav button {
  pointer-events: auto;
}

/* Translucent glass panel behind the bottom bar (wordmark + tabs + the rule
   line above them) -- the bar itself has no other background, so without
   this the text just floats directly over whatever page content scrolls
   underneath it. Height is set so the panel's TOP EDGE lines up exactly
   with the top of .nav-line (60px bottom + 2px height = 62px) -- it must
   stop there, not extend past it, or the blur bleeds upward into the photo
   above the line instead of staying contained to the bar. Sits first in
   .site-nav's DOM order so it paints behind everything else in the nav
   without needing z-index. -webkit- prefix is required for Safari (iOS in
   particular) to actually blur -- plain `background` is the fallback for
   any browser that ignores backdrop-filter entirely. */
.nav-glass {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 62px; /* = .nav-line's bottom (60px) + height (2px) -- keep in sync */
  background: rgba(255, 255, 255, 0.5); /* -5% opacity per request, was 0.55 */
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.nav-wordmark {
  position: absolute;
  left: 24px;
  bottom: 24px;
}

.nav-tabs {
  position: absolute;
  right: 24px;
  bottom: 24px;
  display: flex;
  gap: 20px;
}

/* Thin rule above the bottom bar, spanning the same 24px gutter as the
   wordmark/tabs below it — matches the reference's line-above-caption
   treatment. Sits on the persistent nav layer so it shows on every page. */
.nav-line {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 60px;
  height: 2px;
  background: #000;
}

.nav-toggle {
  position: absolute;
  right: 24px;
  top: 24px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  width: 26px;
  padding: 6px 2px;
}

.nav-toggle span {
  display: block;
  height: 2px; /* was 1px — bolder per request */
  width: 100%;
  background: #000;
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.nav-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}
.nav-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

/* Hide the small persistent tabs while the overlay is open, so the same
   three links aren't shown twice at once (large, centered in the overlay,
   and small, bottom-right). The wordmark stays visible as a home anchor. */
body.nav-open .nav-tabs {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

/* -----------------------------
   4. Overlay menu
   ----------------------------- */
.overlay-menu {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0.62); /* more transparent per request — was 0.82, see .lightbox below (matched) */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0.35s;
}

.overlay-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.overlay-links {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

/* Reverted to the original weight per follow-up feedback — a prior pass
   tried font-weight 700 for "darker", but that read as too bold. Back to
   500 (the original); color stays explicit black. */
.overlay-links a {
  font-size: clamp(28px, 6vw, 56px);
  font-weight: 500;
  color: #000;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  transition: opacity 0.2s ease;
}

.overlay-links a:hover {
  opacity: 0.5;
}

/* Socials sit directly under the links (as their own tight cluster) instead
   of being pinned independently to the viewport bottom — previously that
   put them right at the same height as .nav-line (the persistent thin rule
   above the bottom nav bar, which stays on top at z-index 100 even while
   the overlay is open), so they visually touched/overlapped it. Now they
   flow naturally after "Information" with a close, deliberately tightened
   gap (less than a fresh section's worth of space) rather than being
   anchored to the bottom of the screen. */
.overlay-socials {
  margin-top: 32px;
  display: flex;
  gap: 24px;
}

.overlay-socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; /* was 22px — "a notch bigger" per request */
  height: 28px;
}

.overlay-socials svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: #000;
  stroke-width: 1.4;
}

/* -----------------------------
   5. Homepage
   ----------------------------- */
/* Full-bleed, no borders/gaps, per explicit request (the abbotts.dk-style
   division gap + left/top border gaps "wasn't working visually" -- dropped
   entirely rather than re-tuned). Back to plain full-bleed: the two halves
   touch directly, edge to edge, with nothing between them and nothing
   inset from the viewport's own edges.

   Images are NOT cropped -- each renders at its own natural aspect ratio
   (width:100%, height:auto), and `.hero` only sets a `min-height: 100vh`
   floor, not a forced height: if a photo ends up taller than one screen at
   half-viewport width, the page scrolls a little rather than the image
   getting cropped to fit ("full bleed images with scroll option," her
   words). Worth flagging: if a single hover sequence mixes frames of quite
   different aspect ratios, the crossfade layer below will still stretch
   slightly to match whichever frame is currently establishing the box --
   that trade-off is what this round's "no crop, full bleed" choice
   accepts (the alternative, tried last round, was object-fit:cover, which
   avoided the stretch by cropping the larger frames instead). */
.hero {
  display: flex;
  min-height: 100vh;
  box-sizing: border-box;
  gap: 0;
  padding-bottom: 60px; /* reserves exactly the .nav-line's own distance from
    the viewport bottom (see section 3), so the image ends right above the
    line rather than running underneath it -- unrelated to the design
    borders/gaps removed above, kept per her separate "should end right
    above the nav line" request. */
  background: #fff;
}

.hero-half {
  position: relative; /* positioning context for the absolutely-stacked 2nd img below */
  flex: 1 1 50%;
  cursor: pointer;
}

/* The first (in-flow) <img> of each pair establishes the half's actual
   height -- width:100% of the full-bleed box, height:auto so it's never
   cropped or stretched, just scaled. */
.hero-half img {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity 0.133s linear; /* must match FADE_MS in js/main.js exactly */
}

/* The second <img> is the crossfade layer: absolutely stacked exactly on
   top of the first. With no border gap on either half anymore, inset:0
   lines it up with the first image's box exactly -- no calc() offsets
   needed. See initHeroHalf() in js/main.js for the role-swapping opacity
   logic that makes this a true image-to-image dissolve with no white
   flash. */
.hero-half img:nth-of-type(2) {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* -----------------------------
   6. Editorial page
   ----------------------------- */
/* Shared row-archive system — used by BOTH Editorial and Commission.
   Ref: https://abbotts.dk/work/ — one horizontal row per project: a label
   column on the left (title + subtitle/season), a filmstrip of same-height
   images/videos to the right. Rows are separated by a thin divider line
   with a small corner tick, matching the reference.

   Deviations from the literal reference, per explicit request:
   - The reference butts filmstrip images edge-to-edge with NO gap; here a
     visible gap is added between every image/video (--row-item-gap). */
.archive-page {
  padding: 48px 0 100px;
}

.archive-row {
  display: flex;
  align-items: flex-start;
  gap: 48px;
  padding: 28px 24px; /* was 56px — shrunk so 4-5 projects fit on one screen (see .row-strip) */
}

.row-label {
  flex: 0 0 220px;
  padding-top: 6px;
}

.row-label .title {
  display: block;
  font-weight: 600;
}

.row-label .subtitle {
  display: block;
  color: #666;
  margin-top: 4px;
}

.row-strip {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: stretch;
  gap: 12px; /* was 20px — scaled down to match the smaller thumbnails below */
  height: 18vh; /* was 46vh — shrunk so 4-5 projects fit on one screen, per request.
    Width shrinks along with it automatically: thumbnails are sized by
    height + their own natural aspect ratio (see .row-strip img/video below),
    so there's no separate "width" knob to turn — this one change handles both. */
  min-height: 150px;
  max-height: 220px;
  overflow-x: auto; /* images keep their own natural width instead of being
    stretched, so a row can end up wider than the available space; scroll
    rather than crop or clip anything out of view. */
  overflow-y: hidden;
}

/* Each image/video keeps its OWN natural aspect ratio at the row's shared
   height — no longer force-stretched to equally divide the row's width
   (that was flex:1 1 0 + width:100% + object-fit:cover, which cropped
   anything that didn't match its slot). Per explicit request: never crop,
   and don't try to fill the entire row — a project with fewer/narrower
   images simply leaves empty space at the end of its strip; a project
   whose images add up to more than the available width scrolls
   horizontally instead (see overflow-x above). */
.row-strip img,
.row-strip video {
  flex: 0 0 auto;
  height: 100%;
  width: auto;
  object-fit: contain;
  cursor: pointer;
}

/* No hover dimming — a prior opacity-on-hover effect blended the image with
   the white page background behind it (there's nothing else to blend with
   at less than full opacity), which read as an unwanted white tint over the
   thumbnail. Removed per request; cursor:pointer alone signals click-ability,
   matching the reference. */

/* Lightbox-only extras: images/videos that should be reachable when paging
   through a project's lightbox, but should NOT appear in the filmstrip
   preview on this page (e.g. additional shots that would clutter or
   over-lengthen the row). Add them as extra <img>/<video class="lightbox-extra">
   children at the END of a .row-strip (after the visible ones — see the
   HTML comments in editorial.html/commission.html for why the ordering
   matters on mobile). They never render or take up row space here, on
   either desktop or mobile, but js/main.js's lightbox builder reads every
   IMG/VIDEO child of .row-strip regardless of visibility, so they still
   show up when scrolling through that project's lightbox. */
.row-strip .lightbox-extra {
  display: none;
}

/* Auto-fill (js/main.js): when a row's visible items leave leftover space
   at the row's shared height (natural aspect ratios rarely add up to
   exactly the available width — see "no cropping" above), JS reveals
   lightbox-only extras, in order, until the space is used up. This class
   is added/removed entirely by JS — never add it by hand in the HTML.
   Three classes beats the plain ".lightbox-extra" hide rule above by
   specificity, so this correctly overrides it on desktop. A
   "lightbox-extra-permanent" extra (see HTML) is deliberately excluded by
   the JS and never receives this class, so it stays lightbox-only always. */
.row-strip .lightbox-extra.is-shown {
  display: block;
}

/* Divider between rows: line + small corner tick, matching the reference */
.row-divider {
  position: relative;
  border: none;
  border-top: 2px solid #000;
  margin: 0 24px;
}

.row-divider::after {
  content: "";
  position: absolute;
  right: 0;
  top: -2px;
  width: 2px;
  height: 14px;
  background: #000;
}

/* Editorial and Commission now behave identically on click: every image/
   video in a row opens the shared lightbox below, with left/right paging
   through that SAME row's items — there is no more per-page click
   difference and Commission no longer links out to a separate project
   page (see js/main.js initLightbox for how items are grouped per row). */

/* Lightbox — translucent (frosted) overlay with prev/next gallery paging.
   Clicking any image/video in a row opens it here; left/right arrows page
   through every item in that same project; the close cross returns to
   the underlying Editorial/Commission page (nothing navigates away). */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0.62); /* more transparent per request — was 0.82 */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s;
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.lightbox-media {
  max-height: 88vh;
  max-width: 82vw;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-media img,
.lightbox-media video {
  max-height: 88vh;
  max-width: 82vw;
  width: auto;
  height: auto;
  object-fit: contain;
}

.lightbox-close {
  position: absolute;
  top: 24px;
  right: 24px;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  z-index: 1;
}

.lightbox-prev,
.lightbox-next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  font-size: 32px;
  line-height: 1;
  padding: 12px 18px;
  z-index: 1;
}

.lightbox-prev {
  left: 12px;
}

.lightbox-next {
  right: 12px;
}

.lightbox-prev:hover,
.lightbox-next:hover,
.lightbox-close:hover {
  opacity: 0.6;
}

.lightbox-counter {
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 13px;
  letter-spacing: 0.04em;
}

/* -----------------------------
   7. Commission page
   ----------------------------- */
/* Commission's row/label/filmstrip/lightbox rules are entirely the shared
   .archive-row / .lightbox system above (section 6) — nothing page-specific
   needed here. Commission has no dedicated per-project pages (confirmed) —
   every row opens in the same in-page lightbox gallery as Editorial. */

/* -----------------------------
   8. Information page
   ----------------------------- */
/* Full-bleed split, per explicit request: portrait fills the right half of
   the screen edge to edge (like the homepage hero), bio/contact/social sits
   in the left half, its text ragged-left/flush-right so it reads toward
   the image rather than toward the outer edge of the page. */
.information-page {
  display: flex;
  height: 100vh; /* fixed, not min-height -- keeps the page from scrolling
    now that the text block is vertically centered rather than top-anchored */
  box-sizing: border-box;
  padding-bottom: 60px; /* reserves exactly .nav-line's own distance from the
    viewport bottom (see section 3 and the same fix on .hero), so the
    portrait ends right above the line instead of running underneath it. */
  overflow: hidden;
}

.information-content {
  flex: 1 1 50%;
  display: flex;
  flex-direction: column;
  align-items: flex-end; /* pins each block to the column's right edge, next to the portrait */
  justify-content: center; /* vertically centers the text block instead of
    top-anchoring it -- horizontal (right) alignment above is unchanged */
  text-align: right;
  padding: 40px 40px 40px 24px;
  font-size: 16px;
  line-height: 1.6;
}

/* Cap each block's own width so lines wrap at a readable length instead of
   stretching across the full half-width column -- align-items:flex-end
   above keeps the (narrower) block pinned to the right regardless. */
.information-content > * {
  width: 100%;
  max-width: 520px;
}

.information-portrait {
  flex: 1 1 50%;
  position: relative; /* positioning context for the full-bleed img below */
}

.information-portrait img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.information-content h1 {
  font-size: clamp(26px, 4vw, 36px);
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1; /* strip the inherited 1.6 leading -- that extra space
    above/below the glyphs, not just the margin below, was what kept the
    role line looking far away */
  margin-bottom: 4px;
}

/* Role line under the name -- "Creative Director • Fashion Stylist •
   Brand Consultant". Deliberately not uppercase/bold like the h1 above it,
   so it reads as a subtitle rather than a second heading. */
.information-role {
  font-size: 14px;
  letter-spacing: 0.02em;
  color: #000;
  line-height: 1.2; /* also strip most of the inherited leading above this
    line, so it sits right under the h1 rather than floating below it */
  margin-bottom: 30px;
}

.information-content p {
  margin-bottom: 24px;
}

.information-block {
  margin-top: 40px;
}

.information-block h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 12px;
  font-weight: 700; /* Contact / Social headings -- bold */
}

.information-block a {
  display: block;
  margin-bottom: 6px;
  font-style: italic;
}

/* Plain (non-link) lines inside a block -- e.g. the phone number above the
   email link -- match the tighter line spacing of the links around them
   rather than inheriting .information-content p's larger paragraph gap. */
.information-block p {
  margin-bottom: 6px;
}

/* -----------------------------
   9. Responsive
   ----------------------------- */
/* Hero: single full-bleed column instead of the two-column split whenever
   the viewport is portrait-oriented (taller than wide), regardless of exact
   width -- not just narrow phones. The two-column split only reads well on
   wide/short viewports: at half-width, a 3:4 photo falls far short of a
   tall viewport's height. Landscape tablets and laptops stay on the
   two-column split, which fills correctly there. The plain
   (max-width: 800px) branch still covers narrow *landscape* phones, which
   wouldn't otherwise match the orientation check.

   ONE holder, not two (per explicit request): only the RIGHT sequence is
   used -- the left half is hidden entirely (not just deferred to) rather
   than shown. Swiping through it is handled in js/main.js (touch
   start/end on #hero-right); autoplay/hover still drives it independently
   on desktop, where touch events simply never fire.

   No crop, no stretch: this reverts the previous round's object-fit:cover
   fix. That crop eliminated the blank-gap problem but traded away "no
   crop" -- per her explicit follow-up ("no stretch, no crop if possible"),
   the image goes back to its natural aspect ratio (same technique as the
   desktop two-column hero: an in-flow first <img> establishes the box's
   real height, the crossfade layer matches via inset:0). Whatever gap that
   leaves is resolved by centering the box vertically (`justify-content:
   center` below) instead of top-anchoring it, so any leftover space is
   split evenly above/below rather than dumped in one visible block. */
@media (max-width: 800px), (orientation: portrait) {
  .hero {
    flex-direction: column;
    justify-content: center;
    gap: 0;
    height: 100vh; /* fixed -- gives justify-content:center a real range to
      center within, rather than the min-height floor growing to content */
  }
  .hero-half:first-child {
    display: none;
  }
  .hero-half:last-child {
    flex: 0 0 auto; /* size to the image's own natural height, not stretched
      to fill -- required for vertical centering to have any visible effect */
    width: 100%;
  }
  /* First (in-flow) layer: back to plain natural-aspect flow sizing (no
     absolute/cover crop) -- identical technique to the desktop rule above,
     just re-declared here since the base .hero-half img rule already does
     this and this block only needs to exist to override the crop that used
     to live here. Kept explicit for clarity given how much this block has
     changed round to round. */
  .hero-half:last-child img {
    display: block;
    width: 100%;
    height: auto;
  }
  .hero-half:last-child img:nth-of-type(2) {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }
}

/* -----------------------------
   8b. Information page — tablet (801–1024px, e.g. iPad portrait)
   ----------------------------- */
/* Between the mobile stack (<=800px, unchanged) and full desktop (>1024px,
   unchanged full-bleed split), the page stays side-by-side like desktop,
   but per explicit request the portrait no longer fills the full 100vh
   column edge-to-edge here -- it's resized to match the bio text's actual
   rendered height instead, and both columns are vertically centered
   together so image and text start and end at the same point. The height
   match itself is set inline by js/main.js's syncInformationPortraitHeight()
   (same function that already does this for mobile) -- align-items:center
   below is what stops the columns from stretching to fill the full row so
   that matched height is actually visible as "shorter than 100vh" rather
   than being stretched back out again. */
@media (min-width: 801px) and (max-width: 1024px) {
  .information-page {
    align-items: center;
  }
  .information-portrait {
    flex: 1 1 50%;
    /* height set inline by JS to match .information-content's rendered height */
  }
}

@media (max-width: 800px) {
  .nav-glass {
    height: 48px; /* = mobile .nav-line's bottom (46px) + height (2px) -- keep in sync */
  }
  .nav-wordmark {
    left: 16px;
    bottom: 16px;
    font-size: 13px;
  }
  .nav-tabs {
    right: 16px;
    bottom: 16px;
    gap: 8px;
  }
  .nav-tab {
    font-size: 12px; /* +2px per explicit request */
    letter-spacing: 0.01em;
  }
  .nav-line {
    left: 16px;
    right: 16px;
    bottom: 46px;
  }
  .nav-toggle {
    right: 16px;
    top: 16px;
  }

  /* Row-archive (Editorial + Commission) on mobile: label stacks above a
     SINGLE cover image (not the full filmstrip) — "one cover image
     clickable" per request. The rest of that project's images/videos stay
     in the DOM (just hidden), so tapping the cover still opens the
     lightbox with the complete set browsable via left/right. */
  .archive-row {
    flex-direction: column;
    gap: 16px;
    padding: 24px 16px;
  }
  .row-label {
    flex: none;
    padding-top: 0;
  }
  .row-strip {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 5;
    min-height: 0;
    max-height: none;
  }
  .row-strip img:not(:first-child),
  .row-strip video:not(:first-child) {
    display: none;
  }
  .row-strip img:first-child,
  .row-strip video:first-child {
    flex: 1 1 auto;
    width: 100%;
    height: 100%;
    object-fit: cover; /* fills the uniform 4:5 box edge to edge instead of
      the desktop rule's object-fit:contain (which preserves each photo's
      own aspect and would letterbox a differing source, making covers look
      inconsistent size to size). Recommended export: crop cover images to
      an exact 4:5 ratio (e.g. 1080x1350px) beforehand so nothing is
      cropped unpredictably by this rule -- see build-phase.md for the full
      spec she can hand to a photo folder. */
  }

  /* Explicit mobile cover override: normally the first item in the row is
     the mobile cover (rules above). A project can instead designate ANY
     item as the mobile cover — regardless of its desktop position — by
     adding class="mobile-cover" (see generate_rows.py's mobile_cover_idx).
     When one exists in a strip, hide everything (including the first
     child) and show only the designated item. Used by Bare Bombay and
     Fevicol Shoefix, where the desktop row order and the best mobile cover
     image are no longer the same item. */
  .row-strip:has(.mobile-cover) img,
  .row-strip:has(.mobile-cover) video {
    display: none;
  }
  .row-strip .mobile-cover {
    display: block !important;
    flex: 1 1 auto;
    width: 100%;
    height: 100%;
    object-fit: cover; /* same uniform-fill treatment as the default cover rule above */
  }

  .archive-page {
    padding-top: 56px;
  }

  /* Stack vertically on mobile -- there's no meaningful "left/right" at
     this width. Text keeps its right-alignment (per the same request),
     just full-width instead of pinned to a half-column. */
  .information-page {
    flex-direction: column;
    height: auto; /* reset the desktop-only fixed 100vh -- mobile stacks
      text above a 70vh portrait, which is taller than one screen, so this
      needs to scroll normally rather than being clipped by overflow:hidden */
    min-height: 100vh;
    overflow: visible;
  }
  .information-content {
    justify-content: flex-start; /* vertical centering is a desktop-only
      treatment -- on mobile the column stacks, so keep this top-anchored */
    padding: 64px 24px 16px;
    font-size: 13px; /* down from 16px -- see below, this is what actually
      gets the whole bio to fit in one screen without overlapping the
      fixed footer nav */
    line-height: 1.35; /* down from the inherited 1.6 */
  }
  .information-content > * {
    max-width: 100%;
  }
  /* Tighter vertical rhythm to match the smaller font -- per "bio needs to
     fit on a single page so text and footer don't overlap, can reduce font
     size slightly." Tuned against real small-phone heights (iPhone SE
     375x667, a common small Android at 360x780) so the whole block (h1
     through Social) clears the fixed nav line with the page unscrolled on
     those too, not just a full-size phone; the portrait below is reached
     by scrolling down, which is the intended mobile behavior (see
     .information-portrait above). */
  .information-role {
    margin-bottom: 14px;
  }
  .information-content p {
    margin-bottom: 10px;
  }
  .information-block {
    margin-top: 16px;
  }
  .information-block h2 {
    margin-bottom: 6px;
  }
  /* flex: 0 0 auto (not just height:70vh) -- in a column flex container,
     flex-basis (still 50% from the base rule otherwise) wins over an
     explicit height on the main axis. With the container's height now
     auto/indefinite (min-height:auto above), that 50% resolves like "auto"
     -- i.e. content-based -- and this item's only content is an
     absolutely-positioned img, which contributes nothing to its parent's
     height, collapsing it to 0. Resetting flex-basis here is what actually
     makes the height stick.

     The 70vh below is a fallback only -- js/main.js's
     syncInformationPortraitHeight() measures the bio's actual rendered
     height on load and sets this element's height (via inline style, which
     wins over this rule) to match it exactly, so image and text end up the
     same length. 70vh just covers the instant before that JS runs / a
     no-JS edge case. */
  .information-portrait {
    flex: 0 0 auto;
    height: 70vh;
  }
}

/* Extra-narrow phones (e.g. 320px-wide devices): the 800px breakpoint's nav
   sizing above is tuned for ~360px+; tighten further here so the bold wordmark
   and tab group never collide at the narrowest common width. */
@media (max-width: 340px) {
  .nav-wordmark {
    font-size: 10px; /* nudged down 1px from 11px -- the +2px tab bump below
      needs the extra room at this narrowest tier to avoid colliding with
      the wordmark (verified down to 320px) */
  }
  .nav-tabs {
    gap: 3px;
  }
  .nav-tab {
    font-size: 11px; /* +2px per explicit request */
    letter-spacing: 0;
  }
}
