@charset "UTF-8";
/* ==========================================================================
   Pakdis — gallery archive
   --------------------------------------------------------------------------
   A standalone sheet for gallery.html. It introduces no colour, font, radius
   or easing of its own — everything resolves to the tokens in css/style.css,
   and the header, footer, .plate and .breadcrumb components are used exactly
   as that sheet defines them.

   The tiles are `.gallery__item` from css/style.css, unmodified. That is the
   whole idea of this page and it is worth being explicit about what it buys:
   the component already carries the identity's asymmetric radius
   (14/48/16/16), its gold-duotone resting state, the `--lit` switch to full
   colour, the two foot gradients that swap with it, and the centred caption
   with its 128px rule. None of that is restated here. This file changes the
   container — a scrolling grid instead of a scroll-snap track — and nothing
   else about the card.

   The one thing it does add is the reason the page can be purple at all.
   Sixteen full-colour photographs on a coloured ground fight the ground and
   each other; sixteen gold duotones read as a single field, and lighting one
   at a time gives the archive a focus. The component was already built that
   way for the home page's strip. Here it is doing the same job at scale.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. The ground
   One purple field from under the header to the footer, with the identity's
   pattern across all of it.

   Both live in a single background stack on <body>, painted top to bottom:
   a veil of the brand purple, the pattern sheet, then the brand purple as the
   base colour. The veil is what sets the pattern's strength — white ink at
   full alpha ends up as 12% white over purple once the veil composites over
   it, which is the same result an `opacity` would give without needing a
   second element to carry it.

   Doing it with a pseudo-element is the obvious alternative and it is a trap:
   a negative-z-index child paints *behind* its parent's background unless the
   parent establishes a stacking context, so the pattern disappears under the
   purple and no opacity value brings it back. As background layers there is
   no stacking order to get wrong.
   -------------------------------------------------------------------------- */

.galleryarchive {
  background: var(--purple-flood);
  background:
    linear-gradient(rgb(66 42 116 / .88), rgb(66 42 116 / .88)),
    url("../assets/pattern-gallery.png") center top / cover no-repeat,
    var(--purple-flood);
  background-attachment: fixed, fixed, fixed;
}

/* --------------------------------------------------------------------------
   2. Opening
   `page-hero` is on the section as a behaviour hook — js/app.js keys the
   sticky header's transparent→solid switch off `.hero, .page-hero`. On a page
   that is purple the whole way down the bar has to stay transparent while the
   head is in view and go solid after, so the class is load-bearing here.
   -------------------------------------------------------------------------- */

.garch__head {
  position: relative;
  padding-block: var(--hero-top) 0;
}

.garch__head .breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 14.5px;
  font-weight: 400;
  color: rgba(255, 255, 255, .7);
}
.garch__head .breadcrumb a { color: rgba(255, 255, 255, .7); transition: color .2s var(--ease); }
.garch__head .breadcrumb a:hover { color: var(--gold); }
.garch__head .breadcrumb span { color: #fff; }
.garch__head .breadcrumb__sep {
  flex: none;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .6;
  rotate: 180deg;                      /* RTL: chevron points start-ward */
}

/* -- title + ornament ----------------------------------------------------- */
/* `.section-head` hangs its headline off a percentage of the ornament's height
   and positions it absolutely. That works for a one-line section title and
   breaks the moment the text wraps, so the archive's h1 sits in normal flow
   under the artwork instead. Same asset, same role, no fragile dependency. */




/* -- filters -------------------------------------------------------------- */
/* No rule under the filters. A hairline across the full width cut the head off
   from the grid it controls, and this page has no other lines in it — the row
   of chips is its own object and does not need underlining. The space it took
   goes back to the pictures, which now start 40px higher. */
.garch__filters {
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding-bottom: 0;
}

.chip {
  padding: 10px 20px;
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: rgba(255, 255, 255, .82);
  background: rgb(255 255 255 / .07);
  border: 1px solid rgb(255 255 255 / .18);
  /* The identity's broken corner, at chip scale. */
  border-radius: 999px 999px 999px 6px;
  cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.chip:hover {
  background: rgb(255 255 255 / .12);
  border-color: rgb(187 167 96 / .55);
  color: #fff;
}
.chip:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* The active chip is the one place gold becomes a fill rather than a line —
   it is the page's only selected state and needs to be unmistakable. Purple
   text on it measures 6.9:1. */
.chip.is-on {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--purple);
  font-weight: 700;
  /* Lit rather than merely filled: without this the selected chip sat at the
     same depth as the unselected ones and only colour separated them. */
  box-shadow: 0 10px 24px -12px rgb(187 167 96 / .65);
}
.chip.is-on:hover { background: color-mix(in srgb, var(--gold) 88%, #fff); }

/* The count belongs to the strip, so it is shaped like the chips — same
   height, same broken corner — but outlined instead of filled: it reports,
   it is not a choice. */
.garch__count {
  margin: 0;
  margin-inline-start: auto;
  padding: 10px 18px;
  border: 1px dashed rgb(187 167 96 / .38);
  border-radius: 999px 999px 999px 6px;
  font-size: 13.5px;
  font-weight: 500;
  /* Raw --gold on this purple is 3.4:1, under the 4.5 the system sets for
     body-scale text. Lightened out of the token rather than replaced by a new
     hex: this resolves to 4.7:1. */
  color: color-mix(in srgb, var(--gold) 62%, #fff);
}

/* --------------------------------------------------------------------------
   3. The grid
   Four columns on the artboard, matching the strip's four visible tiles and
   its 24px gutter, so a reader arriving from the home page sees the same
   rhythm — just running down instead of across.
   -------------------------------------------------------------------------- */

.garch { padding-block: 30px 96px; }

.garch__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
  margin: 0;
  padding: 0;
  list-style: none;
  /* CSS Grid auto-placement reads `direction`, so on an RTL page a plain grid
     fills right-to-left. That is correct here and deliberately left alone —
     the reading order and the visual order agree. Noted because .card-grid in
     css/style.css forces ltr for the opposite reason, and the difference
     should not look like an oversight. */
}

/* The tile's height. The component fixes it at 218px for the strip; the
   archive scales it with the column so tiles stay in proportion at every
   width instead of growing wide and staying short. The floor keeps the
   caption's two lines readable, the ceiling stops a wide window turning the
   grid into billboards. */
.garch__cell .gallery__link {
  height: auto;
  aspect-ratio: 4 / 3.35;
  min-height: 218px;
  max-height: 330px;
  transition: transform .4s var(--ease), box-shadow .4s var(--ease);
}
/* The tile comes forward as well as lighting up — two channels for one state,
   so it still reads with the gold hairline switched off. */
.garch__cell:hover .gallery__link,
.garch__cell:focus-within .gallery__link {
  transform: translateY(-4px);
  box-shadow: 0 26px 46px -26px rgb(11 5 32 / .8);
}

/* -- reveal --------------------------------------------------------------- */
/* The resting state for the scroll reveal. `.is-observed` is set by
   js/gallery.js, so the tiles are only ever hidden when something is going to
   show them again — with the script absent this rule never applies and the
   grid renders complete. */
.garch__grid.is-observed > .gallery__item {
  opacity: 0;
  transform: translateY(22px);
}
.garch__grid.is-observed > .gallery__item.is-in {
  opacity: 1;
  transform: none;
  /* The delay is set per tile by column index, so a row arrives as a row. */
  transition:
    opacity .55s var(--ease) var(--reveal-delay, 0ms),
    transform .65s var(--ease) var(--reveal-delay, 0ms);
}

/* A gold hairline that draws itself around a tile on hover. The card's own
   duotone-to-colour switch already carries the state; this only sharpens the
   edge so the lit tile reads as picked up rather than merely brighter. It sits
   outside the frame so it never crops the photograph. */
.garch__cell .gallery__link::before {
  content: "";
  position: absolute;
  inset: -3px;
  z-index: 2;
  border: 1px solid rgb(187 167 96 / .75);
  border-radius: inherit;
  opacity: 0;
  transform: scale(.985);
  transition: opacity .3s var(--ease), transform .35s var(--ease);
  pointer-events: none;
}
.garch__cell:hover .gallery__link::before,
.garch__cell:focus-within .gallery__link::before { opacity: 1; transform: none; }

/* Filtered-out tiles. Last in the file on purpose: `[hidden]` has to beat the
   grid item's own display, and source order is what settles it. */
.garch__grid > .gallery__item[hidden] { display: none; }

.garch__empty {
  margin: 48px 0 0;
  font-size: 16px;
  font-weight: 300;
  text-align: center;
  color: rgba(255, 255, 255, .7);
}

/* --------------------------------------------------------------------------
   4. Footer
   The page is already purple, so the footer's plate must not read as a new
   panel arriving — it continues the ground and deepens it towards the foot.
   -------------------------------------------------------------------------- */

/* .site-footer__inner is markup this page shares with the others but which
   style.css never gives a layout — the footer there relies on its children's
   own margins. Stated so the row is explicit rather than incidental, the same
   way css/news.css, article.css and news-single.css state it. */
.site-footer__inner { display: block; }

.garch__foot { margin-top: 0; }
.garch__foot.plate { background: linear-gradient(180deg, rgb(66 42 116 / 0) 0%, #2a1852 55%, var(--purple-deep) 100%); }

/* --------------------------------------------------------------------------
   5. Lightbox
   -------------------------------------------------------------------------- */

.lbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: clamp(20px, 5vw, 64px);
  background: rgb(11 5 32 / .94);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.lbox[hidden] { display: none; }
.lbox.is-open { opacity: 1; }

.lbox__stage {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 100%;
  margin: 0;
}
.lbox__img {
  display: block;
  max-width: min(100%, 1240px);
  max-height: 72vh;
  width: auto;
  height: auto;
  margin-inline: auto;
  /* The tile's own radius, at full size — the frame the reader clicked is the
     frame that opens. */
  border-radius: 16px 52px 18px 18px;
  background: rgb(68 47 114 / .3);
  box-shadow: 0 50px 90px -40px #000;
}

.lbox__cap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  text-align: center;
}
.lbox__cap b {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.6;
  color: #fff;
}
.lbox__cap i {
  font-size: 13px;
  font-style: normal;
  font-weight: 300;
  color: rgba(255, 255, 255, .68);
}
.lbox__count {
  margin-top: 4px;
  font-size: 12.5px;
  font-weight: 500;
  color: color-mix(in srgb, var(--gold) 62%, #fff);
}

.lbox__close,
.lbox__nav {
  position: absolute;
  display: grid;
  place-items: center;
  padding: 0;
  color: #fff;
  background: rgb(255 255 255 / .1);
  border: 1px solid rgb(255 255 255 / .2);
  border-radius: 50%;
  cursor: pointer;
  transition: background .25s var(--ease), transform .25s var(--ease);
}
.lbox__close:hover,
.lbox__nav:hover { background: rgb(255 255 255 / .2); }
.lbox__close:focus-visible,
.lbox__nav:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

.lbox__close {
  inset-block-start: 24px;
  inset-inline-end: 24px;
  width: 48px;
  height: 48px;
}
.lbox__close svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.lbox__nav {
  inset-block-start: 50%;
  translate: 0 -50%;
  width: 54px;
  height: 54px;
}
.lbox__nav svg { width: 13px; height: 24px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Physical insets, deliberately: these mean "towards the start of the set" and
   "towards the end", and the chevrons inside them are drawn pointing at fixed
   screen edges. Logical properties would flip each button away from its arrow. */
.lbox__nav--prev { right: 24px; }
.lbox__nav--next { left: 24px; }
.lbox__nav--prev:hover { transform: translateX(3px); }
.lbox__nav--next:hover { transform: translateX(-3px); }

body.is-lboxed { overflow: hidden; }

/* -- the thumbnail strip -------------------------------------------------- */
/* Sixteen frames is more than the arrows should have to walk through. The strip
   turns the overlay from a slideshow into an index: a reader can see where they
   are in the set and jump, which is the difference between browsing and
   clicking next until the right picture arrives. */
.lbox__strip {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 14px clamp(16px, 4vw, 56px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  background: linear-gradient(to top, rgb(11 5 32 / .85) 40%, rgb(11 5 32 / 0));
}
.lbox__strip::-webkit-scrollbar { display: none; }

.lbox__thumb {
  flex: none;
  width: 74px;
  height: 50px;
  padding: 0;
  border: 1px solid rgb(255 255 255 / .18);
  /* The card silhouette at its smallest — the broken corner survives even here,
     which is what keeps the strip part of the system. */
  border-radius: 6px 6px 16px 6px;
  background-color: rgb(68 47 114 / .4);
  background-size: cover;
  background-position: 50% 40%;
  /* Unpicked frames sit in the same gold duotone the grid rests in, so the
     strip and the archive behind it speak the same language. */
  filter: grayscale(1) sepia(1) saturate(1.1) brightness(.72);
  opacity: .78;
  cursor: pointer;
  transition: filter .3s var(--ease), opacity .25s var(--ease),
              transform .25s var(--ease), border-color .25s var(--ease);
}
.lbox__thumb:hover { opacity: 1; transform: translateY(-2px); }
.lbox__thumb.is-on {
  filter: none;
  opacity: 1;
  border-color: var(--gold);
  box-shadow: 0 0 0 1px var(--gold);
}
.lbox__thumb:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* The picture fades in once it has actually decoded, so switching frames never
   shows a half-painted image over the one it replaced. */
.lbox__img { opacity: 0; transition: opacity .3s var(--ease); }
.lbox__img.is-ready { opacity: 1; }

/* Room for the strip, so a tall photograph never sits underneath it. */
.lbox__stage { padding-bottom: 86px; }

/* -- back to top ---------------------------------------------------------- */
.totop {
  position: fixed;
  inset-block-end: 26px;
  inset-inline-start: 26px;
  z-index: 120;
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  padding: 0;
  color: var(--purple);
  background: var(--gold);
  border: 0;
  border-radius: 50% 50% 50% 14px;     /* the identity's broken corner */
  cursor: pointer;
  box-shadow: 0 16px 32px -14px rgb(11 5 32 / .8);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity .3s var(--ease), transform .35s var(--ease), visibility .3s;
}
.totop.is-on { opacity: 1; visibility: visible; transform: none; }
.totop:hover { transform: translateY(-3px); }
.totop:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.totop svg {
  width: 20px; height: 20px;
  fill: none; stroke: currentColor;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}

/* --------------------------------------------------------------------------
   6. Responsive — the project's existing breakpoints only.
   -------------------------------------------------------------------------- */

@media (max-width: 1500px) {
  .garch__grid { gap: 20px; }
  .garch__cell .gallery__link { max-height: 300px; }
}

@media (max-width: 1200px) {
  .garch__head { padding-block: var(--hero-top) 0; }
  .garch__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }
  .garch { padding-block: 24px 76px; }
  .garch__filters { padding-bottom: 0; }
}

@media (max-width: 1024px) {
  .garch__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .garch__cell .gallery__link { aspect-ratio: 4 / 3; min-height: 200px; }
  .lbox__nav { width: 48px; height: 48px; }
  .lbox__nav--prev { right: 14px; }
  .lbox__nav--next { left: 14px; }
}

@media (max-width: 620px) {
  .garch__head { padding-block: var(--hero-top) 0; }
  .garch__head .breadcrumb { font-size: 13px; gap: 6px; }

  .garch__filters { gap: 8px; padding-bottom: 0; }
  /* 44px tap target: 12+12 padding around a ~20px line box. */
  .chip { padding: 12px 16px; font-size: 13px; }
  /* An auto margin on a wrapped flex line would strand the count alone on its
     own row against the far edge. */
  .garch__count { margin-inline-start: 0; width: 100%; }

  /* One column. Two tiles side by side under 620px are about 150px wide —
     thumbnails, not photographs, and the caption stops fitting entirely. */
  .garch__grid { grid-template-columns: 1fr; gap: 16px; }
  .garch__cell .gallery__link { aspect-ratio: 16 / 10; min-height: 0; max-height: none; }
  .garch { padding-block: 18px 56px; }

  .lbox { padding: 16px; }
  .lbox__img { max-height: 52vh; border-radius: 12px 38px 14px 14px; }
  .lbox__stage { padding-bottom: 72px; }
  .lbox__strip { gap: 6px; padding: 10px 14px; justify-content: flex-start; }
  .lbox__thumb { width: 58px; height: 40px; }
  .totop { inset-block-end: 16px; inset-inline-start: 16px; width: 46px; height: 46px; }
  .lbox__close { inset-block-start: 14px; inset-inline-end: 14px; width: 44px; height: 44px; }
  .lbox__nav { inset-block-start: auto; inset-block-end: 18px; translate: none; width: 44px; height: 44px; }
  .lbox__nav--prev { right: calc(50% + 10px); }
  .lbox__nav--next { left: calc(50% + 10px); }
}

/* --------------------------------------------------------------------------
   7. Motion preferences
   Extends the block at the end of css/style.css to what this sheet adds.
   Every state here is also carried by colour, so nothing is lost by holding
   it still.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .chip,
  .lbox,
  .lbox__img,
  .lbox__thumb,
  .lbox__close,
  .lbox__nav,
  .totop,
  .garch__cell .gallery__link,
  .garch__cell .gallery__link::before { transition: none; }
  .garch__cell:hover .gallery__link,
  .garch__cell:focus-within .gallery__link { transform: none; }

  /* The reveal is a transition on a hidden resting state, so switching the
     transition off alone would leave every tile invisible. The resting state
     has to be neutralised too. */
  .garch__grid.is-observed > .gallery__item { opacity: 1; transform: none; }
  .totop:hover, .lbox__thumb:hover { transform: none; }

  .lbox__nav--prev:hover,
  .lbox__nav--next:hover { transform: none; }
  .lbox__nav { translate: 0 -50%; }
}
