/* The photograph grids, shared by the front page and /gallery.html.

   One stylesheet because there is one grid in two crops. The front page shows
   a fixed four rows of it (.gallery.home) and links out; the mosaic page shows
   all of it (.gallery.mosaic) with a search over it. Both use the same tile,
   the same caption treatment and the same opened view, so a change to how a
   photograph reads happens once.

   Load theme.css BEFORE this file: every colour here is a token from it.

   index.html keeps the rest of its CSS inline. This block came out of there so
   the mosaic page could have it too, which is worth remembering if you go
   looking for the gallery styles in the page and cannot find them. */

/* =============================================================== headings */

/* Also used for the sub headings in the Code and Contact sections. */
.gallery-head{
  display:flex;justify-content:space-between;align-items:baseline;
  margin:5rem 0 1.6rem;flex-wrap:wrap;gap:1rem;
}
.gallery-head h3{font-size:22px;font-weight:800;letter-spacing:-.01em;}
.gallery-head span{font-size:12px;color:var(--muted);letter-spacing:.08em;text-transform:uppercase;}
.gallery-head .gallery-link{
  color:var(--accent);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:1px;margin-left:.4rem;
}
.gallery-head .gallery-link:hover{border-bottom-color:var(--accent);}

/* ================================================================== tiles */

.gallery{
  display:grid;
  border-top:1px solid var(--line);border-left:1px solid var(--line);
}
.gallery .tile{
  position:relative;overflow:hidden;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--bg-2);display:flex;align-items:flex-end;padding:1rem;
  text-decoration:none;color:var(--fg);
  transition:background-color 220ms ease;
}
.gallery .tile:hover{background:var(--bg-3);}
.gallery .tile img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  /* The focal point is authored per photograph in data/timeline.json, so a
     tall crop of a wide frame keeps the boat rather than centring on whatever
     happens to sit halfway down. */
  object-position:center var(--focus,55%);
  transition:transform 400ms ease, filter 220ms ease;
}
.gallery .tile:hover img,
.gallery .tile:focus-visible img{transform:scale(1.04);}

/* The caption sits on the photograph, so it carries its own ground rather
   than relying on whatever happens to be in the bottom of the frame. */
.gallery .tile::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:60%;
  background:linear-gradient(to top,rgba(0,0,0,.72),rgba(0,0,0,0));
  pointer-events:none;
}
.gallery .tile span{
  position:relative;z-index:1;
  font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  color:#f2f2f0;text-shadow:0 1px 2px rgba(0,0,0,.5);line-height:1.35;
}
/* gallery-search.js filters by setting hidden on the tile. The rule above
   sets display, which outranks the browser's own [hidden] rule, so this has to
   be said here or a filtered out photograph would stay on the page. */
.gallery .tile[hidden]{display:none;}
.gallery[hidden]{display:none;}

.gallery .tile.wide{grid-column:span 2;}
.gallery .tile.tall{grid-row:span 2;}

@media (prefers-reduced-motion:reduce){
  .gallery .tile,.gallery .tile img{transition:none;}
  .gallery .tile:hover img,.gallery .tile:focus-visible img{transform:none;}
}

/* ========================================================== the front page */

/* Four columns and four rows, and it stops there. The build checks that the
   photographs marked for the front page tile this exactly, because the whole
   point is a grid that ends where it says it does: see scripts/lib/grid.mjs.

   Rows track the column width so a single tile stays near the 3:2 of the
   photographs and cover has almost nothing to crop. */
.gallery.home{
  grid-template-columns:repeat(4,minmax(0,1fr));
  grid-auto-rows:clamp(150px,15vw,240px);
}

@media (max-width:820px){
  /* Two columns cannot tile those spans, and a phone that scrolls through the
     whole set buries everything under it, so the layout changes rather than
     reflowing: the lead photograph across both columns, then six in pairs.
     Four rows again, and the rest are one tap away on the mosaic page. */
  .gallery.home{
    grid-template-columns:repeat(2,minmax(0,1fr));
    grid-auto-rows:clamp(118px,33vw,180px);
  }
  .gallery.home .tile{grid-column:auto;grid-row:auto;}
  .gallery.home .tile.lead{grid-column:span 2;}
  .gallery.home .tile:nth-child(n+8){display:none;}
}

/* ========================================================== the mosaic page */

.gallery.mosaic{
  /* Six, four and three, rather than whatever fits: the tiles span two columns
     or two rows, so the column count decides whether the set tiles cleanly or
     leaves gaps in it. These three were measured against the photographs that
     are actually in the file. */
  grid-template-columns:repeat(6,minmax(0,1fr));
  grid-auto-rows:clamp(130px,9.5vw,170px);
  /* Filtering takes tiles out of the middle of the grid, so the rest has to
     close up behind them rather than leaving the holes they came out of. */
  grid-auto-flow:dense;
}
@media (max-width:1200px){
  .gallery.mosaic{grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:clamp(140px,14vw,200px);}
}
@media (max-width:900px){
  .gallery.mosaic{grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:21vw;}
}
@media (max-width:560px){
  /* Thumbnails, three across: a mosaic that reads as one on a phone instead of
     a column of postcards two dozen screens long. The caption comes back when
     the photograph is opened, and the alt text was never in the way. */
  .gallery.mosaic{grid-auto-rows:26vw;}
  .gallery.mosaic .tile{padding:0;}
  .gallery.mosaic .tile span,
  .gallery.mosaic .tile::after{display:none;}
}

/* ============================================================== the search */

/* Mirrors the control bar on /timeline.html. It is a copy rather than a shared
   block because that one lives in timeline.css with the rest of that page; if
   you restyle one, restyle both. */

.gal-controls{border:1px solid var(--line);margin-bottom:2.4rem;}
.gal-controls[hidden]{display:none;}

.gal-row{
  display:flex;flex-wrap:wrap;align-items:center;gap:.7rem 1.4rem;
  padding:1rem 1.4rem;
}
.gal-row + .gal-row{border-top:1px solid var(--line);}

.gal-field{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1.1rem;flex:1 1 26ch;}
.gal-field label,.gal-label{
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);flex:none;
}
.gal-controls input[type="search"],
.gal-controls select{
  font:inherit;font-size:13px;color:var(--fg);
  background:var(--bg-2);border:1px solid var(--line);
  padding:.5rem .7rem;min-width:0;
  transition:border-color 220ms ease;
}
.gal-controls input[type="search"]{flex:1 1 14ch;}
.gal-controls select{cursor:pointer;max-width:100%;}
.gal-controls input[type="search"]:focus,
.gal-controls select:focus{outline:none;border-color:var(--accent);}
.gal-controls input[type="search"]::placeholder{color:var(--muted);opacity:.75;}

.gal-field-where{flex:0 1 auto;}

.gal-chips{display:flex;flex-wrap:wrap;gap:.5rem;flex:1 1 auto;}

.gal-chip,.gal-filter{
  display:inline-flex;align-items:center;gap:.5rem;cursor:pointer;
  font-size:12.5px;color:var(--muted);white-space:nowrap;
}
.gal-chip{border:1px solid var(--line);padding:.35rem .6rem;}
.gal-chip:hover,.gal-filter:hover{color:var(--fg);}
.gal-chip:hover{border-color:var(--muted);}
.gal-chip input,.gal-filter input{accent-color:var(--accent);width:15px;height:15px;cursor:pointer;}
/* A chip whose box is ticked reads as on at a glance, without relying on the
   size of a checkbox to carry it. */
.gal-chip:has(input:checked){color:var(--fg);border-color:var(--accent);}
.gal-chip:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px;}

.gal-n{
  font-size:10.5px;letter-spacing:.06em;color:var(--muted);
  border-left:1px solid var(--line);padding-left:.5rem;
}

.gal-reset{
  margin-left:auto;font:inherit;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  background:transparent;color:var(--fg);border:1px solid var(--line);
  padding:.5rem .9rem;cursor:pointer;
  transition:border-color 220ms ease,color 220ms ease;
}
.gal-reset:hover{border-color:var(--accent);color:var(--accent);}

.gal-count{
  font-size:12px;letter-spacing:.06em;color:var(--muted);
  padding:0 1.4rem 1rem;
}
.gal-count[hidden]{display:none;}

.gal-empty{
  border:1px dashed var(--line);color:var(--muted);
  font-size:13.5px;line-height:1.6;padding:1.6rem 1.8rem;
  max-width:70ch;margin-top:2.4rem;
}
.gal-empty[hidden]{display:none;}

@media (max-width:560px){
  .gal-row{padding:.9rem 1rem;}
  .gal-reset{margin-left:0;}
}

/* ======================================================= the opened photo */

/* Built by /assets/gallery.js, which is also the only thing that ever unhides
   it, so nothing here shows without script. */
.lightbox{
  position:fixed;inset:0;z-index:400;
  display:flex;align-items:center;justify-content:center;
  padding:clamp(.8rem,3vw,2.4rem);
  background:rgba(8,8,10,.9);
}
.lightbox[hidden]{display:none;}
.lb-figure{
  display:flex;flex-direction:column;min-width:0;
  max-width:min(1180px,100%);max-height:100%;
  background:var(--bg);border:1px solid var(--line);
}
.lb-figure img{
  display:block;margin:0 auto;
  max-width:100%;max-height:min(70vh,calc(100vh - 16rem));
  width:auto;height:auto;object-fit:contain;background:var(--thumb-bg);
}
.lb-figure figcaption{
  padding:1.2rem 1.4rem;border-top:1px solid var(--line);
  overflow-y:auto;
}
.lb-count{
  font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  margin-bottom:.5rem;
}
.lb-title{font-size:16px;font-weight:700;letter-spacing:-.01em;}
.lb-detail{font-size:13.5px;line-height:1.6;color:var(--muted);max-width:70ch;margin-top:.5rem;}
.lb-event{
  font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
  margin-top:.9rem;padding-top:.9rem;border-top:1px solid var(--line);
}
.lb-event a{margin-left:.5rem;color:var(--accent);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:1px;}
.lb-event a:hover{border-bottom-color:var(--accent);}
.lb-event[hidden],.lb-event a[hidden]{display:none;}
.lb-btn{
  position:absolute;z-index:1;
  width:38px;height:38px;padding:0;
  display:flex;align-items:center;justify-content:center;
  background:var(--bg-2);border:1px solid var(--line);color:var(--muted);
  font-family:inherit;font-size:18px;line-height:1;cursor:pointer;
  transition:color 220ms ease,border-color 220ms ease;
}
.lb-btn:hover{color:var(--accent);border-color:var(--accent);}
.lb-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.lb-close{top:clamp(.8rem,3vw,2.4rem);right:clamp(.8rem,3vw,2.4rem);}
.lb-prev{left:clamp(.4rem,2vw,1.4rem);top:50%;transform:translateY(-50%);}
.lb-next{right:clamp(.4rem,2vw,1.4rem);top:50%;transform:translateY(-50%);}
@media (max-width:820px){
  /* No room to flank the photograph on a phone, so the arrows sit under it. */
  .lb-prev,.lb-next{top:auto;bottom:.6rem;transform:none;}
  .lb-prev{left:.6rem;}
  .lb-next{right:.6rem;}
  .lb-figure{margin-bottom:3.4rem;}
}
