/* ==========================================================================
   andyrepton.com

   Photographs lead; the writing is deadpan, so body copy stays plain and lets
   the jokes land on their own. Clean neutral surfaces, one accent colour
   (pine), one modern typeface (Manrope) carrying both display and body text.

   The one ornamental device is "horizon" - a slim accent line standing in
   for the skylines and coastlines in the photos themselves. Used as a
   section rule. Nowhere else.
   ========================================================================== */

:root {
  --paper:  #f5f6f7; /* cool neutral, not cream - base background */
  --raised: #ffffff; /* card / raised surface */
  --ink:    #16181b; /* body text, cool near-black */
  --soft:   #5b6167; /* secondary text */
  --rule:   #e2e4e7; /* hairlines */

  /* Single accent. Used for links, emphasis, and the one ornamental line -
     nowhere else, so it never competes with itself. */
  --pine: #14746b;

  --sans: 'Manrope', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  /* Condensed uppercase display face for the masthead only - matches the
     old Squarespace site's wordmark/nav treatment. */
  --display: 'Oswald', ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;

  --measure: 36rem;
  --wide:    68rem;
  --space:   1.4rem;

  --shadow-sm: 0 1px 2px rgba(22, 24, 27, 0.06), 0 1px 1px rgba(22, 24, 27, 0.04);
  --shadow-md: 0 10px 30px -12px rgba(22, 24, 27, 0.22);
}

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

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

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.62;
}

.wrap { max-width: var(--wide); margin: 0 auto; padding: 0 1.5rem; }

/* .measure narrows the text without moving the left edge. Applying a smaller
   max-width to .wrap itself would re-centre the block and break alignment with
   every other section, so constrain the children instead. */
/* Constrain the children only. Setting max-width on .measure itself would
   override .wrap's own max-width (equal specificity, later in the file), which
   drops the centring and shunts the whole section to the viewport edge. */
.measure > * { max-width: var(--measure); }

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 1rem; top: 1rem; z-index: 20;
  background: var(--raised); padding: 0.5rem 0.9rem;
  border: 1px solid var(--pine); border-radius: 4px; box-shadow: var(--shadow-md);
}

a { color: var(--pine); text-underline-offset: 0.15em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }

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

/* Horizon - the one ornament on the site. */
.horizon {
  height: 3px; border: 0; margin: 0; border-radius: 999px;
  background: var(--pine);
  box-shadow: 0 4px 14px -4px rgba(20, 116, 107, 0.4);
}

.masthead { padding: 1.8rem 0 1.3rem; }
.masthead .wrap {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.6rem 2rem;
}
/* Bold, tracked capitals for the masthead - lifted from the old
   Squarespace site's nav treatment, which read as more confident/branded
   than a plain lowercase wordmark. */
.wordmark { font-family: var(--display); font-size: 1.2rem; font-weight: 600;
            text-transform: uppercase; letter-spacing: 0.06em;
            text-decoration: none; color: var(--ink); }
.masthead nav ul { display: flex; flex-wrap: wrap; gap: 0.4rem 1.6rem;
                   margin: 0; padding: 0; list-style: none; font-size: 0.85rem; }
.masthead nav a { font-family: var(--display); color: var(--soft); text-decoration: none;
                  padding-bottom: 3px; font-weight: 500; text-transform: uppercase;
                  letter-spacing: 0.06em;
                  border-bottom: 1px solid transparent; transition: color 0.15s, border-color 0.15s; }
.masthead nav a:hover { color: var(--pine); }
.masthead nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--pine); }

main { padding-bottom: 4.5rem; }
.hero { padding: clamp(2.5rem, 6vw, 4.5rem) 0 0; }

/* Condensed display face for every heading, not just the masthead - matches
   the old site's "Who I am" / "Talks" / "Contact me" treatment: large,
   narrow, medium weight rather than heavy. */
h1 { margin: 0 0 0.9rem; font-family: var(--display);
     font-size: clamp(2.6rem, 1.6rem + 4.8vw, 4.6rem);
     font-weight: 500; line-height: 1.0; letter-spacing: 0; }

.standfirst { margin: 0; max-width: 32rem; text-wrap: pretty;
              font-size: clamp(1.1rem, 1rem + 0.6vw, 1.4rem); }
/* Two of these can sit stacked (photos page's two-line intro) - margin:0
   above means they'd otherwise touch with no gap. */
.standfirst + .standfirst { margin-top: 0.6rem; }

/* Full-bleed photo hero. Not called .hero: the other pages use plain .hero
   (a simple padding-only section) for text-only intros, and must not
   inherit any of this. The photo is the whole section background (not a
   cropped inset) with the masthead floating over it, per the Squarespace
   "Quinn"/"Amal" pattern this was benchmarked against: photo first, text
   over it, nothing competing for the same space. .hero-full--compact is
   the shorter variant for a secondary page's header banner, as opposed to
   the homepage's full room-filling hero. */
.hero-full {
  position: relative;
  min-height: min(94vh, 820px);
  display: flex;
  overflow: hidden;
  background: var(--ink); /* shows briefly if the photo is slow to paint */
}
.hero-full--compact { min-height: min(56vh, 480px); }
.hero-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 32%;
  /* Parallax target on the homepage - see home.js. Scaled up slightly so
     the parallax translation never reveals an edge. Harmless on pages
     without the script, since nothing then moves it. */
  transform: scale(1.08); transform-origin: center 32%;
  will-change: transform;
}
/* The photos-page banner's focal point (the lantern corridor's vanishing
   point) sits right of the source photo's horizontal centre - shift the
   crop window right (which moves the visible content left) so it lands in
   the middle of the page. Scoped to this one banner, not the homepage
   hero, which shares .hero-img but has its own correct framing. */
.hero-full--compact .hero-img { object-position: 85% 32%; transform-origin: 85% 32%; }
.hero-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(10, 10, 11, 0.55) 0%, rgba(10, 10, 11, 0.08) 32%,
                     rgba(10, 10, 11, 0.15) 55%, rgba(10, 10, 11, 0.75) 100%);
}
.hero-inner {
  position: relative; z-index: 1; width: 100%; min-height: inherit;
  display: flex; flex-direction: column; justify-content: space-between;
}
.hero-full .masthead { padding: 1.6rem 0; }
.hero-full .wordmark { color: var(--raised); }
.hero-full .masthead nav a { color: rgba(255, 255, 255, 0.78); }
.hero-full .masthead nav a:hover { color: var(--raised); }
.hero-full .masthead nav a[aria-current="page"] { color: var(--raised); border-bottom-color: var(--raised); }
.hero-content { padding-bottom: clamp(2.75rem, 7vw, 5.5rem); color: var(--raised); }
.hero-content h1 {
  color: var(--raised); text-shadow: 0 2px 28px rgba(0, 0, 0, 0.45);
  max-width: 22ch;
}
.hero-content .standfirst {
  color: rgba(255, 255, 255, 0.92); text-shadow: 0 1px 16px rgba(0, 0, 0, 0.4);
}

@media (max-width: 40rem) {
  .hero-full { min-height: min(100vh, 640px); }
  .hero-full--compact { min-height: min(60vh, 420px); }
}

.eyebrow { display: block; margin: 0 0 0.6rem;
           font-size: 0.78rem; font-weight: 700; letter-spacing: 0.09em;
           text-transform: uppercase; color: var(--pine); }
h2 { margin: 0 0 0.5rem; font-family: var(--display);
     font-size: clamp(1.8rem, 1.5rem + 1.2vw, 2.4rem);
     font-weight: 500; letter-spacing: 0; }
.section { padding: clamp(3.25rem, 6vw, 5.5rem) 0 0; }
/* A shorter top gap for a section that's just a line or two of text right
   under a header banner (e.g. the photos page's title/standfirst) - the
   normal section padding is sized for content-heavy sections and reads as
   too much air around one short paragraph. */
.section--tight { padding-top: clamp(1.75rem, 3.5vw, 2.5rem); }
.section-note { margin: 0 0 1.8rem; color: var(--soft); font-size: 0.95rem; font-style: italic; }

/* Experience gets a raised card rather than sitting flush on the page -
   the one section with enough content to earn its own surface. */
.panel { background: var(--raised); border: 1px solid var(--rule); border-radius: 14px;
         box-shadow: var(--shadow-md); padding: clamp(1.4rem, 4vw, 2.2rem) clamp(1.4rem, 4vw, 2.4rem); }
.panel .feats { max-width: none; }

/* "Elsewhere" as tappable pills instead of a middle-dot-separated line. */
.pill-row { display: flex; flex-wrap: wrap; gap: 0.65rem; margin: 0; }
.pill-link { display: inline-flex; align-items: center; padding: 0.5rem 1.15rem;
             border-radius: 999px; background: var(--raised); border: 1px solid var(--rule);
             color: var(--ink); text-decoration: none; font-size: 0.92rem; font-weight: 600;
             box-shadow: var(--shadow-sm);
             transition: border-color 0.15s, color 0.15s, transform 0.15s, box-shadow 0.15s; }
.pill-link:hover { border-color: var(--pine); color: var(--pine); transform: translateY(-1px);
                    box-shadow: var(--shadow-md); }

/* Scroll reveal - homepage only, JS-added class (see home.js). Sections are
   fully visible with no JS at all; this only adds the entrance animation. */
.reveal-init { opacity: 0; transform: translateY(22px); transition: opacity 0.7s ease, transform 0.7s ease; }
.reveal-visible { opacity: 1; transform: translateY(0); }

p { margin: 0 0 var(--space); }
.measure > :last-child { margin-bottom: 0; }

/* Experience & feature lists rendered as a soft timeline: a gradient spine
   with a small marker per entry, rather than plain bordered rows. Purely
   decorative, purely CSS (::before/::after), no markup required. */
.feats { margin: 0; padding: 0; list-style: none; max-width: 44rem;
         position: relative; }
.feats::before {
  content: ""; position: absolute; left: 3px; top: 0.5rem; bottom: 0.5rem;
  width: 2px; background: var(--pine); opacity: 0.35;
}
.feats li { padding: 0.85rem 0 0.85rem 1.8rem; position: relative; text-wrap: pretty; }
.feats li + li { border-top: 1px solid var(--rule); }
.feats li::before {
  content: ""; position: absolute; left: 0; top: 1.5rem;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--raised); border: 2px solid var(--pine);
}

/* Experience: same list, but each entry is a role/company/dates/summary
   stack rather than one line, so the marker sits against the first line
   only and the row gets more vertical room. */
.roles li { padding-top: 1.1rem; padding-bottom: 1.1rem; }
.roles li::before { top: 1.65rem; }
.roles .role { margin: 0 0 0.2rem; font-size: 1.08rem; font-weight: 700; }
.roles .role-meta { margin: 0 0 0.5rem; color: var(--soft); font-size: 0.86rem;
                     text-transform: uppercase; letter-spacing: 0.04em; }
.roles .role-desc { margin: 0; font-size: 0.98rem; text-wrap: pretty; }

/* Carousel: CSS scroll-snap plus anchor links, so it needs no JavaScript -
   script-src 'none' stays true on this page, same as every page but the
   homepage and /contact/. Full viewport width per slide, arrows baked into
   each figure (not one shared pair - there's no JS to know which slide is
   current, so every figure carries its own correctly-targeted prev/next
   links, wrapping around at the ends) and revealed only on hover/focus. */
.carousel { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
            overscroll-behavior-x: contain; }
.carousel figure { flex: 0 0 100%; scroll-snap-align: start; margin: 0; }

/* Scrollbar hidden - scroll/swipe/snap still work via trackpad, wheel or
   touch, the thumbnail strip covers click-to-jump. */
.carousel { scrollbar-width: none; }
.carousel::-webkit-scrollbar { display: none; }

/* Letterboxed, not cropped: object-fit:contain shows each photo at its own
   aspect ratio (portrait stays portrait) inside a fixed-height frame, so
   the slide height stays consistent without stretching or cutting any
   photo down to a forced shape. */
.carousel-frame {
  position: relative; height: clamp(320px, 78vh, 760px);
  display: flex; align-items: center; justify-content: center;
  background: var(--ink);
}
.carousel-frame img {
  display: block; max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain;
}

.carousel-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 3rem; height: 3rem; border-radius: 50%;
  background: rgba(10, 10, 11, 0.35); backdrop-filter: blur(3px);
  color: var(--raised); text-decoration: none; font-size: 1.3rem;
  opacity: 0; transition: opacity 0.2s ease, background 0.2s ease;
}
.carousel-arrow:hover { background: rgba(10, 10, 11, 0.6); }
.carousel-arrow.prev { left: 1.25rem; }
.carousel-arrow.next { right: 1.25rem; }
/* Hover-only, deliberately - no touch-device fallback. A mouse hovering the
   photo is the only thing that reveals these. */
figure:hover .carousel-arrow,
figure:focus-within .carousel-arrow { opacity: 1; }

/* Caption on hover: an overlay at the foot of the frame, hidden until the
   photo is hovered or focused - same trigger as the arrows - rather than a
   caption permanently sitting below the image. A gradient scrim underneath
   keeps it legible over whatever the photo is doing at that edge. */
.carousel-caption-scrim {
  position: absolute; inset: auto 0 0 0; height: 45%;
  background: linear-gradient(to top, rgba(10, 10, 11, 0.85), transparent);
  opacity: 0; transition: opacity 0.2s ease; pointer-events: none;
}
.carousel figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  margin: 0; padding: 1.75rem;
  font-size: 0.96rem; color: rgba(255, 255, 255, 0.92); text-wrap: pretty;
  opacity: 0; transition: opacity 0.2s ease;
}
.carousel figcaption b { color: var(--raised); font-weight: 700; }
figure:hover .carousel-caption-scrim, figure:focus-within .carousel-caption-scrim,
figure:hover figcaption, figure:focus-within figcaption { opacity: 1; }

/* Thumbnail strip, replacing numbered nav - small previews people can
   actually recognise rather than counting to a number. Fixed box, both
   width and height, with object-fit:cover cropping each one to fit -
   letting either dimension run free (fixed-height-only, or
   fixed-width-only) looked bad in both directions once portrait and
   landscape photos sat in the same strip, since the two orientations are
   roughly inverse ratios of each other. Cropping here is fine: the main
   viewer above already shows every photo uncropped, this row's job is only
   recognition. */
.carousel-thumbs { display: flex; gap: 0.6rem; overflow-x: auto;
                    margin: 1.4rem 0 0; padding: 0.25rem 0.25rem 0.5rem; }
.carousel-thumbs img {
  display: block; width: 5.5rem; height: 3.7rem; flex: 0 0 auto;
  object-fit: cover; border-radius: 6px; border: 1px solid var(--rule);
  box-shadow: var(--shadow-sm); opacity: 0.75;
  transition: opacity 0.15s, border-color 0.15s, transform 0.15s;
}
.carousel-thumbs a:hover img,
.carousel-thumbs a:focus-visible img { opacity: 1; border-color: var(--pine); transform: translateY(-2px); }

@media (max-width: 40rem) {
  .carousel figure { flex-basis: 100%; }
}

/* Two-column contact layout - text/email on the left, location/map on the
   right, matching the old site. Collapses to a single column on narrow
   screens, map second. */
.contact-grid { display: grid; grid-template-columns: 1.1fr 0.9fr;
                gap: clamp(2rem, 5vw, 4rem); align-items: start; }
@media (max-width: 48rem) { .contact-grid { grid-template-columns: 1fr; } }
.contact-email-block { margin-top: clamp(2rem, 4vw, 3rem); }

.location { display: flex; flex-wrap: wrap; align-items: baseline;
            gap: 0.5rem 0.9rem; margin: 0 0 1.2rem; }
.location .where { font-size: 1.7rem; font-weight: 800; letter-spacing: -0.01em; }
.location .since { color: var(--soft); font-size: 0.95rem; }

#map { height: clamp(280px, 45vh, 440px); border: 1px solid var(--rule);
       border-radius: 10px; box-shadow: var(--shadow-md); overflow: hidden;
       background: var(--rule); }
.map-fallback { padding: 1.2rem; color: var(--soft); font-size: 0.95rem; }
.contact-email { font-size: 1.2rem; font-weight: 700; }

.colophon { margin-top: 4rem; padding: 1.4rem 0 3rem; border-top: 1px solid var(--rule);
            font-size: 0.85rem; color: var(--soft); }
.colophon p { margin: 0; }
