/* ==========================================================================
   COMPONENTS — one block per piece of the interface.
   ========================================================================== */

/* --------------------------------------------------------------------------
   BRAND  (JAMES WANG wordmark + JW logo)
   -------------------------------------------------------------------------- */

   .brand__name {
    font-family: var(--font-body);
    font-weight: var(--w-bold);
    font-size: var(--fs-name);
    line-height: var(--lh-tight);
    text-transform: capitalize;
  }
  .service__name {
    font-family: var(--font-body);
    font-weight: var(--w-semibold);
    font-size: var(--fs-service);
    line-height: var(--lh-tight);
    text-transform: capitalize;
  }
  
  /* block + a narrow max-width is what breaks JAMES / WANG onto two lines.
     These margins only reach the desktop sidebar — the topbar overrides them
     below.                                                                   */
  .brand__name { display: block; max-width: 10ch; margin-top: 12px; }
  .service__name { display: block; max-width: 15ch; margin-top: 10px; }
  
  .brand__logo { width: var(--logo-w); margin-top: 0; }
  
  /* In the mobile topbar the logo sits beside the name, so the sidebar's
     stacking offsets and line-break width are cancelled here.                */
  /* --logo-w-topbar is set on .topbar in layout.css; the fallback keeps the
     image from falling back to its natural size if that rule is missing.   */
  .topbar .brand__logo   { width: var(--logo-w-topbar, var(--logo-w)); margin-top: 0; flex: 0 0 auto; }
  .topbar .brand__name    { margin-top: 0; max-width: none; white-space: nowrap; }
  .topbar .service__name  { margin-top: 2px; max-width: none; white-space: nowrap; }
  
  /* --------------------------------------------------------------------------
     NAV
     -------------------------------------------------------------------------- */
  
  .nav { margin-top: 94px; }
  
  .nav__item + .nav__item { margin-top: calc(var(--nav-step) - 1.2em); }
  
  .nav__link {
    display: inline-block;
    font-size: var(--fs-nav);
    font-weight: var(--w-semibold);
    line-height: var(--lh-tight);
    text-transform: uppercase;
    opacity: var(--o-nav-idle);
    transition: opacity var(--dur) ease;
  }
  
  .nav__link:hover,
  .nav__link:focus-visible,
  .nav__item[aria-current="page"] .nav__link { opacity: 1; }
  
  .nav__social {
    display: inline-block;
    margin-top: 44px;
    opacity: var(--o-nav-idle);
    transition: opacity var(--dur) ease;
  }
  .nav__social:hover, .nav__social:focus-visible { opacity: 1; }
  .nav__social svg { display: block; width: 25px; height: 25px; }
  
  /* --------------------------------------------------------------------------
     MOBILE MENU  (the + button and the panel it opens)
     -------------------------------------------------------------------------- */
  
  .menu-toggle { width: 30px; height: 30px; position: relative; flex: 0 0 auto; }
  .menu-toggle::before,
  .menu-toggle::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--c-text);
    transition: transform var(--dur) ease;
  }
  .menu-toggle::after { transform: rotate(90deg); }
  [data-menu-open] .menu-toggle::after { transform: rotate(0deg); }
  
  .menu {
    display: none;
    padding: 30px 0 40px;
    text-align: center;
  }
  [data-menu-open] .menu { display: block; }
  
  .menu .nav { margin-top: 0; }
  .menu .nav__item + .nav__item { margin-top: calc(var(--menu-step) - 1.2em); }
  .menu .nav__social { margin-top: 25px; }
  
  /* --------------------------------------------------------------------------
     GRID  — shared by the homepage cards and the project galleries.
     Widths are percentages, so the whole thing is fluid.
     -------------------------------------------------------------------------- */
  
  .grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--row-gap) var(--col-gap);
  }
  
  .grid > .col-full  { flex: 0 0 100%; }
  .grid > .col-half  { flex: 0 0 calc((100% - var(--col-gap)) / 2); }
  .grid > .col-third { flex: 0 0 calc((100% - var(--col-gap) * 2) / 3); }
  
  /* On a phone everything stacks: one item per row, whatever its desktop span. */
  @media (max-width: 767px) {
    .grid > .col-full,
    .grid > .col-half,
    .grid > .col-third { flex-basis: 100%; }
  }
  
  /* --------------------------------------------------------------------------
     CARD  — a project on the homepage or in "Other Projects"
     -------------------------------------------------------------------------- */
  
  .card__media {
    overflow: hidden;
    aspect-ratio: var(--card-ratio);
  }
  
  .card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: opacity var(--dur) ease, transform .4s cubic-bezier(.2,.6,.2,1);
  }
  
  .card:hover .card__media img,
  .card:focus-visible .card__media img {
    opacity: var(--o-hover-image);
    transform: scale(1.03);
  }
  
  .card__title {
    margin-top: var(--card-title-gap);
    font-size: var(--fs-card-title);
    font-weight: var(--w-xbold);
    line-height: var(--lh-tight);
  }
  
  .card__meta {
    margin-top: var(--card-meta-gap);
    font-size: var(--fs-card-meta);
    font-weight: var(--w-light);
    line-height: var(--lh-tight);
    color: var(--c-text-muted);
  }
  
  /* smaller variant used under "Other Projects" */
  .card--related .card__title { font-size: var(--fs-related-title); font-weight: var(--w-bold); }
  .card--related .card__meta  { font-size: var(--fs-related-meta); color: var(--c-text); }
  
  /* --------------------------------------------------------------------------
     PROJECT PAGE
     -------------------------------------------------------------------------- */
  
  .project__title {
    font-size: var(--fs-page-title);
    font-weight: var(--w-bold);
    line-height: var(--lh-tight);
  }
  
  .project__medium {
    margin-top: 20px;
    font-size: var(--fs-body);
    font-weight: var(--w-regular);
    line-height: var(--lh-tight);
  }
  .project__medium span { font-weight: var(--w-xlight); }
  
  .gallery { margin-top: 80px; }
  .gallery { --row-gap: 23px; }              /* galleries sit tighter than the card grid */
  
  .gallery figure { overflow: hidden; }
  .gallery img { width: 100%; }
  
  /* Optional: add `caption: '...'` to a gallery item in data.js to label it. */
  .gallery__caption {
    margin-top: 20px;
    font-size: var(--fs-card-meta);
    font-weight: var(--w-light);
    line-height: var(--lh-tight);
    color: var(--c-text-muted);
  }
  
  /* Optional: give an item a fixed shape so two side-by-side images match.
     Set style="--ratio: 0.88" on the figure.                                  */
  .gallery figure[style*="--ratio"] img {
    aspect-ratio: var(--ratio);
    object-fit: cover;
    height: 100%;
  }
  
  /* Two columns between the title and the gallery: the medium on the left,
     brief stacked over process on the right.                                 */
  
  .specs {
    margin-top: 52px;
    --row-gap: 34px;
  
    /* 30 / 15 / 55 — the middle value is the empty channel between the two
       columns, so all three add up to the full row. Tune them here.         */
    --specs-meta-w: 30%;
    --specs-gap:    15%;
  
    column-gap: var(--specs-gap);   /* replaces the grid's default gap */
  }
  
  .specs__col--meta { flex: 0 0 var(--specs-meta-w); }
  .specs__col--text { flex: 0 0 calc(100% - var(--specs-meta-w) - var(--specs-gap)); }
  
  /* Brief and process sit in the same column, so they need their own gap. */
  .specs__item + .specs__item { margin-top: 34px; }
  
  .specs__label {
    font-weight: var(--w-bold);
    line-height: var(--lh-tight);
  }
  .specs__body { margin-top: 12px; font-size: var(--fs-prose); }
  
  @media (max-width: 767px) {
    .gallery { margin-top: 40px; }
    .specs   { margin-top: 40px; --row-gap: 28px; }
    .specs__col--meta, .specs__col--text { flex-basis: 100%; }
    .specs__item + .specs__item { margin-top: 28px; }
  }
  
  /* --------------------------------------------------------------------------
     SECTIONS
     -------------------------------------------------------------------------- */
  
  .section { margin-top: 150px; }
  .section__title {
    font-size: var(--fs-section);
    font-weight: var(--w-xbold);
    line-height: var(--lh-tight);
    text-transform: uppercase;
    margin-bottom: 50px;
  }
  
  @media (max-width: 767px) {
    .section { margin-top: 70px; }
    .section__title { margin-bottom: 30px; }
  }
  
  /* --------------------------------------------------------------------------
     BIO + CONTACT
     -------------------------------------------------------------------------- */
  
  /* Three columns on desktop: portrait, the write-up, then the facts.
     The portrait and facts hold their widths; the write-up takes the slack,
     capped at its own measure so the lines stay readable.                    */
  .bio {
    --bio-portrait-w: 30%;   /* share of the row taken by the portrait */
    --bio-facts-w:    28%;   /* share taken by Education / Key Skills  */
  
    display: flex;
    flex-wrap: wrap;
    gap: var(--col-gap);
    align-items: flex-start;
  }
  
  /* The three shares add up to exactly one row once the two gaps are taken
     out, so the columns scale with the page instead of wrapping when the
     content column gets narrower.                                          */
  .bio__portrait {
    flex: 0 0 calc(var(--bio-portrait-w) - var(--col-gap) * 2 / 3);
    width: auto;
    min-width: 0;            /* or the image claims its natural width */
  }
  .bio__text {
    flex: 1 1 calc(100% - var(--bio-portrait-w) - var(--bio-facts-w)
                        - var(--col-gap) * 2 / 3);
    min-width: 0;
    max-width: 565px;
    font-size: var(--fs-prose);
  }
  .bio__text p + p { margin-top: 1.45em; }
  .bio__facts {
    flex: 0 0 calc(var(--bio-facts-w) - var(--col-gap) * 2 / 3);
    min-width: 0;
  }
  
  .bio__facts h2 {
    font-size: var(--fs-heading);
    font-weight: var(--w-semibold);
    line-height: 1.48;
    text-transform: uppercase;
  }
  .bio__facts p, .bio__facts ul { font-size: var(--fs-prose); }
  .bio__facts h2 + p, .bio__facts h2 + ul { margin-top: 4px; }
  .bio__facts > * + h2 { margin-top: 1.45em; }
  
  .bio__poster { width: 100%; margin-top: 45px; }
  
  /* Below this the three columns are too narrow to read, so the write-up
     takes the full width and the portrait drops underneath it.             */
  @media (max-width: 1299px) {
    .bio__text     { flex: 1 1 100%; order: 1; }
    .bio__portrait { flex: 0 1 380px; order: 2; margin-top: 45px; }
    .bio__facts    { flex: 1 1 100%; order: 3; margin-top: 45px; }
  }
  
  /* The animated mark that replaces the old intro line.
     The gif carries about 16% empty space along its bottom edge, so the
     negative margin claws that back and lets the text below sit at a real
     gap. It is a share of the width, so it keeps up if the width changes.   */
  .contact__mark {
    --contact-mark-w:    225px;
    --contact-mark-trim: calc(var(--contact-mark-w) * 0.12);
  
    display: block;
    width: var(--contact-mark-w);
    height: auto;
    margin-bottom: calc(var(--contact-mark-trim) * -1);
  }
  
  .contact__intro { font-size: var(--fs-body); }
  .contact__details {
    margin-top: 30px;
    font-size: var(--fs-contact);
    font-weight: var(--w-medium);
    line-height: 1.5;
  }
  .contact__details a { transition: opacity var(--dur) ease; }
  .contact__details a:hover { opacity: .7; }
  
  @media (max-width: 767px) {
    .card__title { font-weight: var(--w-bold); }
  
    .contact__mark { --contact-mark-w: 188px; }
  
    /* Stacked, and the portrait drops to the bottom where the big one used
       to sit. `order` does the reordering, so the HTML stays as it is.       */
    .bio { flex-direction: column; gap: 0; }
    .bio__portrait { flex: 0 0 auto; width: 100%; margin-top: 45px; order: 3; }
    .bio__text  { flex: 0 0 auto; max-width: none; order: 1; }
    .bio__facts { flex: 0 0 auto; margin-top: 40px; order: 2; }
  }