/*
Theme Name: Ogbonna
Theme URI: https://bradogbonna.com
Author: Brad Ogbonna
Description: Minimal image-forward portfolio theme. Full-bleed slideshow home, click-through project viewers, a Motion section, and a per-section thumbnail index.
Version: 4.5
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: ogbonna
*/

/* ============================================================
   TOKENS — the only numbers you should need to change
   ============================================================ */

:root {
  --bg:   #FFFFFF;
  --ink:  #111111;
  --mute: #999999;
  --hair: #E5E5E5;

  --accent: #D8321E;    /* the red slash in Prev / Next — the only colour */

  --nav-h: 46px;        /* top nav height */

  /* Bottom-left navigation — two lines in the site's own type. The bar
     grows to fit them, and every image sizes itself around that. */
  --bar-size: 12px;
  --bar-gap: 7px;       /* space between PREV / NEXT and SHOW THUMBNAILS */
  --bar-pad-b: 15px;    /* space below the bottom line */
  --bar-h: calc(var(--bar-size) * 2 + var(--bar-gap) + var(--bar-pad-b) + 14px);
  --sidebar-w: 210px;   /* project sidebar */

  /* Image scale — the white border around every frame.
     --slide-x is the margin left and right, --slide-y top and bottom.
     Both apply to portrait and landscape alike, so a tall frame sits
     inside the same border as a wide one. Lower them for bigger
     images, raise them for more white. */
  --slide-x: 1.6vw;
  --slide-y: 2.4vh;

  /* Captions now sit on the photograph itself, so no band is reserved
     for them and the picture keeps that height.

     --frame-h is the height every photo is drawn at: the window, less
     only the thin white border. Both navigation bars float over it. */
  --frame-h: calc(100svh - var(--slide-y) * 2);
  --stage-w: calc(100vw - var(--slide-x) * 2);

  /* Thumbnail sheet. --sheet-h is the height every thumbnail stands at,
     regardless of whether it's a vertical or a horizontal. Widths follow
     from each image's shape. */
  --sheet-gap-x: 14px;
  --sheet-gap-y: 14px;
  --sheet-h: 290px;

  /* Width of the photo on the Info page. */
  --info-img-w: 220px;

  --pad: 22px;
}

/* ============================================================
   RESET
   ============================================================ */

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

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 12px;
  line-height: 1.45;
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { display: block; max-width: 100%; height: auto; }

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

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 2px;
}

.screen-reader-text {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--bg);
  padding: 10px 14px;
}
.skip-link:focus { left: 0; }

/* ============================================================
   TOP NAV
   ============================================================ */

/* The menu floats over whatever is behind it and inverts against it:
   black over the white page, white where a photograph passes beneath.
   That lets a photo use the full height of the window without the menu
   becoming unreadable where the two meet. */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 60;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--pad);
  background: transparent;
  mix-blend-mode: difference;
  color: #FFFFFF;
}

/* .over is what the home page already asked for; the treatment is now
   the default, so the class simply changes nothing. */
.nav.over { background: transparent; }

.wordmark {
  font-weight: 500;
  letter-spacing: 0.02em;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 20px;
}

.nav-right a[aria-current="page"],
.nav-right .work[aria-current="true"] { text-decoration: underline; text-underline-offset: 3px; }

/* Work dropdown */
.work { position: relative; cursor: default; }

.work-list {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  flex-direction: column;
  gap: 6px;
  padding: 10px 0 0;
  white-space: nowrap;
}
.work:hover .work-list,
.work:focus .work-list,
.work:focus-within .work-list { display: flex; }

.menu-btn { display: none; }

/* ============================================================
   VIEWER — one image at a time, used by home, projects, motion
   ============================================================ */

/* The photo runs to the top of the window and passes under the menu,
   which floats over it. That reclaims the height the menu used to
   reserve. The bottom navigation keeps its own band so the caption sits
   on white and the red slash stays red. */
.viewer {
  position: relative;
  height: 100vh;
  height: 100svh;
  margin-top: 0;
  overflow: hidden;
}

/* A project page keeps its sidebar, so the picture has that much less
   width to work with. */
.has-sidebar { --stage-w: calc(100vw - var(--sidebar-w) - var(--slide-x) * 2); }

.slide {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--slide-y) var(--slide-x);
}
.slide.on { display: flex; }



/* Portrait: as tall as the stage allows, minus the border. */
/* The figure shrink-wraps the photograph exactly, so a caption placed
   at its bottom edge always lands on the picture and never on white
   beside it — which matters for a wide panorama that doesn't fill the
   height. */
.frame {
  position: relative;
  display: block;
  max-width: var(--stage-w);
  max-height: var(--frame-h);
  margin: 0;
}

.frame img {
  display: block;
  width: auto;
  height: auto;
  max-width: var(--stage-w);
  max-height: var(--frame-h);
}

/* Portrait: the full height of the window, less the border. */
.slide.is-portrait .frame img {
  height: var(--frame-h);
  width: auto;
}

/* Landscape: as wide as the stage allows, minus the border, and
   capped by the height so a very wide frame gains side margin rather
   than losing its top and bottom. */
.slide.is-landscape .frame img,
.slide.is-square .frame img {
  width: auto;
  height: auto;
  max-width: var(--stage-w);
  max-height: var(--frame-h);
}

/* Every photo is centred. Pinning frames to the left or right edge
   looked lively in the abstract, but with a tall picture in a wide
   window it pooled all the white on one side and the page read as
   half-empty. To bring the placement back, restore these:

     .slide.pos-left  { justify-content: flex-start; }
     .slide.pos-right { justify-content: flex-end; }

/* Caption — the attachment's Caption field, set on the photograph
   itself, centred along its bottom edge. White with a soft shadow so it
   holds on a pale frame as well as a dark one. It doesn't intercept
   clicks, so the left/right advance zones still work beneath it. */
.slide-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 14px;
  z-index: 7;
  margin: 0;
  text-align: center;
  color: #FFFFFF;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}

/* White type alone disappears on a high-key frame, so a caption brings
   a faint shadow up from the bottom edge with it. Only a photo that
   carries a caption gets one; every other frame is untouched. */
.frame:has(.slide-caption)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 96px;
  z-index: 6;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0));
  pointer-events: none;
}

/* Click zones — right half forward, left half back. */
.zone {
  position: absolute;
  top: 0; bottom: 0;
  width: 50%;
  z-index: 5;
  background: transparent;
}
.zone.prev { left: 0;  cursor: w-resize; }
.zone.next { right: 0; cursor: e-resize; }

/* These are mouse conveniences layered over the image, each a half-width
   box taller than the window. A focus ring on one drew its inner edge as
   a hairline straight down the middle of the page. They're out of the tab
   order now — keyboard users get Prev and Next in the bar, which show
   focus properly — and this makes sure no ring can appear on them. */
.zone:focus,
.zone:focus-visible { outline: none; }

/* Home slideshow runs the full height of the window. The nav and the
   bar float over it, so the image still sits inside the same border
   as everywhere else. */
.viewer.full {
  height: 100vh;
  height: 100svh;
  margin-top: 0;
}

/* The home slideshow is sized exactly like every other viewer now. */

/* ============================================================
   PREV / NEXT / INDEX BAR — the same on every section
   ============================================================ */

/* Two lines, bottom left, in capitals:

     PREV / NEXT
     SHOW THUMBNAILS

   The slash is the only colour on the page. Sits above the thumbnail
   sheet, so the same button reads "Hide thumbnails" and closes it. */
.bar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 90;
  height: var(--bar-h);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  padding: 0 var(--pad) var(--bar-pad-b);
  background: transparent;
}

/* The bottom navigation floats over the picture so the picture keeps
   that height, and inverts against whatever is behind it: black over
   the white page, white where a photograph passes beneath. The invert
   has to be set on the bar itself — a blend on the text inside it would
   have nothing to blend against — so it takes the slash with it, and
   the slash reads as plain type rather than red. Swapping back to a
   white band under the bar (and a photo ~7% shorter) restores it. */
.bar {
  mix-blend-mode: difference;
  color: #FFFFFF;
}

.bar-nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--bar-gap);
  font-size: var(--bar-size);
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.bar-step { white-space: nowrap; }
.bar-slash  { color: inherit; opacity: 0.65; }

.bar-index { text-transform: uppercase; }

.bar-nav a:hover,
.bar-index:hover { opacity: 0.55; }

.bar button[disabled],
.bar a[aria-disabled="true"] {
  color: #777777;
  cursor: default;
  pointer-events: none;
}

.bar-meta {
  color: #AAAAAA;
  display: flex;
  align-items: center;
  gap: 14px;
}

/* White, because the blend above inverts it: black on the page,
   white where a photograph is behind it. */
.bar-title { color: #FFFFFF; }

/* On project pages the bar clears the sidebar. */
.has-sidebar .bar { left: var(--sidebar-w); }

/* On the home page the bar floats over the slideshow's white margin.
   The image stops short of it, so no blend trick is needed — and the
   red slash stays red. */
.bar.over { background: transparent; }

/* ============================================================
   INDEX SHEET — the thumbnail overlay, one per section
   ============================================================ */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: var(--bg);
  overflow-y: auto;
  padding: calc(var(--nav-h) + 12px) var(--pad) calc(var(--bar-h) + 32px);
  display: none;
}
.sheet.open { display: block; }

.sheet-head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 14px;
  background: var(--bg);
}

/* Rows of uniform height rather than columns of uniform width. Every
   thumbnail stands the same height and takes whatever width its shape
   needs, so a vertical reads as narrow and a horizontal as wide, and
   the two can be compared at a glance. --sheet-h is the single number
   to change; the rows reflow around it. */
.sheet-grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sheet-gap-y) var(--sheet-gap-x);
  align-items: flex-start;
}

.sheet-item {
  display: block;
  width: auto;
  text-align: left;
}
.sheet-item img {
  height: var(--sheet-h);
  width: auto;
  max-width: none;
}
.sheet-item.is-current img { outline: 1px solid var(--ink); outline-offset: 3px; }

.sheet-cap {
  display: block;
  padding-top: 6px;
  color: var(--mute);
}

/* Motion posters stand the same height as everything else, with 16:9
   fixing their width. */
.sheet-item.motion .poster {
  position: relative;
  display: block;
  height: var(--sheet-h);
  aspect-ratio: 16 / 9;
  background: #EEEEEE;
  overflow: hidden;
}
.sheet-item.motion .poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ============================================================
   SELECT WORK — the landing grid
   ============================================================ */

/* A heading per section — Projects, then Commissions. Set in the same
   quiet type as the sidebar's group labels rather than as a display
   heading, so the photographs stay the loudest thing on the page. */
.work-heading {
  margin: 0;
  padding: 0 var(--pad) 12px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--mute);
}
.work-heading:first-child { padding-top: calc(var(--nav-h) + 24px); }
.work-heading + .work-grid + .work-heading { padding-top: 56px; }

.work-grid {
  padding: 0 var(--pad) 48px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
.work-grid:last-child { padding-bottom: 80px; }

.work-card { position: relative; display: block; }
.work-card img { width: 100%; height: auto; }

.work-card .cap {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 14px 16px;
  color: #FFFFFF;
  font-weight: 700;
  opacity: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.45), rgba(0,0,0,0));
  transition: opacity 120ms linear;
}
.work-card:hover .cap,
.work-card:focus-visible .cap { opacity: 1; }

/* ============================================================
   PROJECT PAGES — persistent sidebar + viewer
   ============================================================ */

.project-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
}

.sidebar {
  position: fixed;
  top: var(--nav-h);
  bottom: var(--bar-h);
  left: 0;
  width: var(--sidebar-w);
  padding: 8px var(--pad) 20px;
  overflow-y: auto;
}

.sidebar ul { list-style: none; margin: 0; padding: 0; }
.sidebar li { padding: 3px 0; }
.sidebar a[aria-current="page"] { text-decoration: underline; text-underline-offset: 3px; }
.sidebar .group {
  color: var(--mute);
  padding: 16px 0 4px;
}
.sidebar .group:first-child { padding-top: 0; }

.project-main { grid-column: 2; }

/* ============================================================
   MOTION
   ============================================================ */

.motion-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--slide-x);
}

.motion-embed {
  width: 100%;
  max-width: calc((100vh - var(--nav-h) - var(--bar-h)) * 16 / 9);
  aspect-ratio: 16 / 9;
  background: #000000;
}
.motion-embed iframe,
.motion-embed video {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* A URL pasted into the editor body arrives wrapped in WordPress's own
   embed markup, which brings its own aspect-ratio boxes and margins.
   Flatten those so the player fills the frame either way. */
.motion-embed figure,
.motion-embed .wp-block-embed,
.motion-embed .wp-block-embed__wrapper,
.motion-embed p {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
.motion-embed .wp-block-embed__wrapper::before { display: none; }

.motion-empty {
  color: var(--mute);
  text-align: center;
  padding: 40px var(--pad);
}

/* Motion landing grid */
.motion-grid {
  margin-top: var(--nav-h);
  padding: 24px var(--pad) 80px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
.motion-grid .poster {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #EEEEEE;
  overflow: hidden;
}
.motion-grid .poster img { width: 100%; height: 100%; object-fit: cover; }
.motion-grid .cap { padding-top: 8px; }
.motion-grid .client { color: var(--mute); }

/* ============================================================
   INFO
   ============================================================ */

.info-doc {
  margin-top: var(--nav-h);
  padding: 28px var(--pad) 80px;
  max-width: none;
}

/* Four columns at 3 / 2 / 2 / 2. The bio column being half again as
   wide as the others is what stops the page reading as a table — the
   short bio leaves a deep well of white before the client list starts.
   Core Columns block does the layout so the page stays editable. */
.info-doc .wp-block-columns {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
}
.info-doc .wp-block-column { min-width: 0; }

/* Section labels. Typed in sentence case in the editor and set in caps
   here, so the caps are a display choice rather than something baked
   into the content. */
.info-doc h2 {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.25;
  margin: 0 0 14px;
}

/* Bio column: larger, with open leading. */
.info-doc p {
  font-size: 16px;
  line-height: 1.625;
  margin: 0 0 16px;
}

/* Client and publication columns: a size down, with the leading pulled
   tight inside each entry and the air placed between entries instead.
   Long names like "The Elder Statesman" then wrap as one compact unit
   rather than opening a gap mid-name. */
.info-doc ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.info-doc li {
  font-size: 14px;
  line-height: 1.25;
  margin: 0 0 14px;
}

/* Lists sit under a label of the same size, so the label column reads
   a step smaller than the bio. */
.info-doc .wp-block-column:not(:first-child) h2 { font-size: 14px; }

.info-doc em,
.info-doc i { font-style: italic; }

.info-doc a { text-decoration: underline; text-underline-offset: 2px; }
.info-doc a:hover { opacity: 0.5; }

/* The Info page photo. Capped at --info-img-w rather than filling its
   column, so it stays modest on large screens. The !important beats any
   width or height WordPress writes onto a resized image block. */
.info-doc figure,
.info-doc .wp-block-image {
  margin: 0 0 28px;
  width: auto !important;
  max-width: var(--info-img-w);
}
.info-doc img {
  width: 100% !important;
  max-width: var(--info-img-w);
  height: auto !important;
}

/* Trailing credit line, set quiet. */
.info-doc .credit { color: var(--mute); }

/* ============================================================
   MOBILE
   ============================================================ */

@media (max-width: 800px) {
  :root {
    --slide-x: 6px;
    --slide-y: 6px;
    /* A phone has no room to spare, so the picture still clears the
       menu and the bottom navigation there. */
    --frame-h: calc(100svh - var(--nav-h) - var(--bar-h) - var(--slide-y) * 2);
    --stage-w: calc(100vw - var(--slide-x) * 2);
    --bar-pad-b: 16px;
    --sheet-h: 175px;
    --pad: 14px;
  }

  .menu-btn { display: block; }

  .nav-right {
    display: none;
    position: absolute;
    top: var(--nav-h);
    left: 0; right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 14px var(--pad) 20px;
    background: var(--bg);
    color: var(--ink);
  }
  .nav.is-open .nav-right { display: flex; }
  .nav.is-open { mix-blend-mode: normal; background: var(--bg); color: var(--ink); }

  .work-list { position: static; display: flex; padding: 8px 0 0 12px; }

  .work-grid, .motion-grid { grid-template-columns: 1fr; gap: 20px; }

  /* Sidebar becomes a scrolling row of project names above the image. */
  .project-shell { display: block; }
  .project-main { grid-column: auto; }
  .sidebar {
    position: static;
    width: auto;
    margin-top: var(--nav-h);
    padding: 8px var(--pad);
    overflow-x: auto;
    white-space: nowrap;
    border-bottom: 1px solid var(--hair);
  }
  .sidebar ul { display: inline-flex; gap: 14px; }
  .sidebar .group { display: none; }
  .has-sidebar .bar { left: 0; }
  /* With the project list as a strip above the picture, the frame has
     that much less height again. */
  .has-sidebar {
    --frame-h: calc(100svh - var(--nav-h) - var(--bar-h) - 40px - var(--slide-y) * 2);
    --stage-w: calc(100vw - var(--slide-x) * 2);
  }
  .has-sidebar .viewer { margin-top: 0; height: calc(100svh - var(--nav-h) - var(--bar-h) - 40px); }

  .bar-meta .bar-count { display: none; }

  /* Info columns stack in source order, and the type steps down a size
     the way the reference does below its desktop breakpoint. */
  .info-doc { padding-top: 24px; }
  .info-doc .wp-block-columns { gap: 0; flex-wrap: wrap; }
  .info-doc .wp-block-column { flex-basis: 100% !important; margin-bottom: 24px; }
  .info-doc p { font-size: 14px; }
  .info-doc li,
  .info-doc h2 { font-size: 12px; }
  .info-doc li { margin-bottom: 10px; }
}

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