/* ==========================================================================
   site.css: every page's styles, in one file.

   Each page's <body> carries a class that says which part applies:
     .sphere    the homepage (index.html)
     .page      the grid pages: the archive, auto_NS and the project pages,
                which add .archive, .autons or .project
     .ibyib     I believe you into being (projects/ibyib/), its own world

   Contents
     1. Shared: tokens, reset, selection
     2. The homepage sphere
     3. Grid pages: base type and layout
     4. Project pages
     5. The archive
     6. auto_NS
     7. I believe you into being

   Breakpoint: phones are up to 768px wide, everywhere.
   ========================================================================== */


/* ==========================================================================
   1. SHARED
   ========================================================================== */

:root {
  --page: #f3f3f3;
  --ink: #111;
  --font: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
  /* The nav row on the homepage and the archive: every button this tall,
     this far apart. The two navs are identical in size; change them here. */
  --bar-h: 1.6rem;
  --bar-gap: 0.5rem;
}

* {
  box-sizing: border-box;
}

/* Buttons cannot be selected, so a quick double-click does not highlight
   their labels. */
button {
  user-select: none;
  -webkit-user-select: none;
}

/* Selected text: orange, text staying black. On the archive, whose page is
   that orange, the darker orange of its pressed buttons, so a selection
   still shows. */
.sphere ::selection,
.page ::selection {
  background: orange;
  color: black;
}

.archive ::selection {
  background: #cc8400;
}


/* ==========================================================================
   2. THE HOMEPAGE SPHERE
   The work titles are real DOM text on an invisible sphere you spin by
   dragging; a fast spin hands them over to WebGL ribbons (#gl). See
   sphere.md before changing anything here.
   ========================================================================== */

html:has(body.sphere) {
  height: 100%;
}

body.sphere {
  height: 100%;
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font);
  overflow: hidden;
  cursor: grab;
  /* A drag is navigation, not a text selection. Without this, spinning the
     sphere sweeps a highlight across every title it passes over. */
  user-select: none;
  -webkit-user-select: none;
  /* On touch, a drag is a spin: not a scroll, not a pinch zoom, and no grey
     flash on tap. The open work's text can still scroll (see #panel). */
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}

body.sphere.dragging {
  cursor: grabbing;
}

/* Shown instead of the page on a device that cannot run the ribbons. */
.sphere .unsupported {
  position: fixed;
  inset: 0;
  margin: 0;
  padding: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 0.9rem;
  line-height: 1.5;
  cursor: auto;
}

/* ---- The two layers
   The ribbons (#gl) sit above the titles: a title fades back in underneath
   its ribbon while the ribbon wipes off. Both stay under the nav. #gl is
   transparent where nothing is drawn, so the page stays the page.
   Titles stay real DOM text: they are billboarded, so there is nothing to
   gain from rendering them in WebGL. */
.sphere #gl {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  z-index: 2;
}

.sphere #titles {
  position: fixed;
  inset: 0;
  z-index: 1;
}

.sphere .title {
  position: absolute;
  top: 0;
  left: 0;
  white-space: nowrap;
  font-size: 1.1875rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  /* Padding grows the hit area; the matching negative margin keeps the type
     exactly where it was, so only the target gets bigger. */
  padding: 0.7rem 0.9rem;
  margin: -0.7rem -0.9rem;
  cursor: pointer;
  will-change: transform, opacity;
}

/* ---- INFO and ARCHIVE are not works, so on the sphere they are buttons,
   bevelled like Shuffle and the filters. In thumb view they show thumbs like
   everything else. Before the thumb-view and filter rules, which must win over
   its label's display. */
.sphere .title.btn .label {
  display: inline-block;
  padding: 0.3rem 0.5rem;
  background: var(--page);
  color: black;
  border: 1px solid;
  border-color: #a8a8a8 #5a5a5a #5a5a5a #a8a8a8;
}

.sphere .title.btn:hover .label {
  background: #e0e0e0;
}

.sphere .title.btn:active .label {
  background: #d0d0d0;
  border-color: #5a5a5a #c4c4c4 #c4c4c4 #5a5a5a;
}

/* Opened (INFO), it is the heading of what opens, not a button: plain bold
   type like any work's title. */
.sphere .title.btn.open .label,
.sphere .title.btn.open:hover .label,
.sphere .title.btn.open:active .label {
  padding: 0;
  background: none;
  border-color: transparent;
}

/* ---- Thumb view (the colour block): each name is swapped for its work's
   image, in place. */
.sphere .title .thumb {
  display: none;
  -webkit-user-drag: none;
  width: auto;
  height: clamp(2.4rem, 5.2vw, 5rem);
}

/* The logo is solid letters edge to edge, so at a photo's height it reads far
   bigger than one. INFO's thumb is a share of the height (INFO_THUMB in the
   script; its ribbon is sized to match). */
.sphere .title.about .thumb {
  height: calc(clamp(2.4rem, 5.2vw, 5rem) * 0.4);
}

.sphere.imgmode .title .label {
  display: none;
}

.sphere.imgmode .title .thumb {
  display: block;
}

/* ...except the open one, which reads as its name while the panel is up. */
.sphere.imgmode .title.open .label {
  display: inline;
}

.sphere.imgmode .title.open .thumb {
  display: none;
}

/* ---- Filtered out: a work the filters hide leaves a twinkling star in its
   place, as on heavenlybodi.es. The script sets its glyph and size every
   frame. */
.sphere .title .star {
  display: none;
  font-size: 1.4rem;
  font-weight: 400;
  line-height: 1;
  will-change: transform;
}

.sphere .title.filtered .label,
.sphere .title.filtered .thumb {
  display: none;
}

.sphere .title.filtered .star {
  display: inline-block;
}

/* ---- The open work. Its title has turned to the front of the sphere and
   sits at the centre; this opens underneath it. The page is not
   selectable, so a drag spins rather than highlights; the open work's text
   is, so its links and the email can be copied. */
.sphere #panel {
  position: fixed;
  left: 50%;
  top: 32%;
  transform: translateX(-50%) translateY(0.5rem);
  width: min(78rem, 90vw);
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
  opacity: 0;
  pointer-events: none;
  z-index: 300;
  transition: opacity 0.28s ease, transform 0.28s ease;
  user-select: text;
  -webkit-user-select: text;
  cursor: auto;
}

.sphere #panel.on {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}

/* No object-fit and no fixed width: the image keeps its own proportions and
   is bounded only by how much room there is. Forcing every one into the same
   box made them all read as squares. */
.sphere #panel img {
  width: auto;
  max-width: 50%;
  max-height: 56vh;
}

.sphere #panel .txt {
  flex: 1;
  max-width: 34rem;
  font-size: 0.8rem;
  line-height: 1.75;
}

.sphere #panel .yr {
  display: block;
  opacity: 0.45;
  margin-bottom: 0.4rem;
}

.sphere #panel .body {
  display: block;
}

.sphere #panel .body p {
  margin: 0 0 0.75em;
}

.sphere #panel .body p:last-child {
  margin-bottom: 0;
}

.sphere #panel .subtitle {
  font-style: italic;
}

/* soft's name is in stylised letters, which run small. */
.sphere #panel .soft {
  font-size: 1rem;
}

.sphere #panel a {
  color: orange;
  text-decoration: underline;
}

/* [ close ], under the text. It looks like text but is a button, so it
   cannot be selected: tapping selectable text on a phone pops up the
   browser's "search for this" prompt. (Tried and rejected: a bevelled
   Close button like the nav's, and an x in the top right corner.) */
.sphere #panel .close {
  display: block;
  margin: 1rem 0 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  opacity: 0.45;
  cursor: pointer;
}

.sphere #panel .close:hover {
  opacity: 0.9;
}

/* ---- The nav, top left, one row: logo, Shuffle, the colour block, then the
   filters. Every item is --bar-h tall and --bar-gap apart, except logo to
   Shuffle and colour block to All, which are three gaps. */
.sphere header {
  position: fixed;
  left: 2rem;
  top: 2rem;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: calc(3 * var(--bar-gap));
  cursor: auto;
}

/* The logo image has no padding above or below the letters, so its box
   height is the letters' height. */
.sphere header img.icon {
  display: block;
  height: var(--bar-h);
  width: auto;
  cursor: pointer;
}

.sphere header .bar {
  display: flex;
  align-items: center;
  gap: var(--bar-gap);
}

/* Three gaps between the colour block and the filters: two more on top of
   the row's own. */
.sphere header .filters {
  display: flex;
  align-items: center;
  gap: var(--bar-gap);
  margin-left: calc(2 * var(--bar-gap));
}

/* A fixed height with the label centred, rather than a height that falls out
   of font size, line height, padding and border. */
.sphere #shuffle,
.sphere .filter-button {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1;
  height: var(--bar-h);
  padding: 0 0.375rem;
  margin: 0;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  background: var(--page);
  color: black;
  border: 1px solid;
  border-color: #a8a8a8 #5a5a5a #5a5a5a #a8a8a8;
}

.sphere #shuffle:hover,
.sphere .filter-button:hover {
  background: #e0e0e0;
}

.sphere #shuffle:active,
.sphere .filter-button:active,
.sphere .filter-button.btnSelected {
  background: #d0d0d0;
  border-color: #5a5a5a #c4c4c4 #c4c4c4 #5a5a5a;
}

.sphere .filter-button .filter-count {
  font-size: 0.7rem;
  font-weight: 400;
  color: #888;
}

/* The colour block (thumb view): a glitching rainbow swatch with a noise
   layer over it that tracks the pointer (--noise-grad, set by the script). */
.sphere #colorblock {
  position: relative;
  flex: none;
  width: var(--bar-h);
  height: var(--bar-h);
  margin: 0;
  border: 1px outset ButtonBorder;
  padding: 0;
  overflow: hidden;
  cursor: help;
  background: transparent;
}

.sphere #colorblock::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    90deg,
    red 0%, red 8%, lime 8%, lime 16%, cyan 16%, cyan 24%,
    magenta 24%, magenta 32%, yellow 32%, yellow 40%, blue 40%, blue 48%);
  background-size: 200% 100%;
  animation: glitchShift 0.2s steps(6) infinite, hueCycle 1.2s linear infinite;
}

.sphere #colorblock::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: var(--noise-grad, repeating-linear-gradient(
    90deg, transparent 0%, rgba(0, 0, 0, 0.3) 10%, transparent 20%));
  background-size: 0.5rem 100%;
  mix-blend-mode: difference;
  opacity: 0.9;
}

@keyframes glitchShift {
  from { background-position: 0 0; }
  to   { background-position: -100% 0; }
}

@keyframes hueCycle {
  from { filter: hue-rotate(0deg); }
  to   { filter: hue-rotate(360deg); }
}

/* ---- The bottom corners: the hint, bottom left, and "Granada, Spain" and
   the time, bottom right. Black, at the nav buttons' size, each in a row the
   nav's height, so they sit as far from the bottom as the nav does from the
   top. */
.sphere #hint,
.sphere #where {
  position: fixed;
  bottom: 2rem;
  z-index: 5;
  height: var(--bar-h);
  display: flex;
  align-items: center;
  font-size: 0.9rem;
  color: black;
}

.sphere #hint {
  left: 2rem;
}

.sphere #where {
  right: 2rem;
}

/* ---- Phones
   The nav splits into two rows (logo, Shuffle and the colour block; then the
   filters), the edge margins drop to 1rem, titles go back to their original
   size and may wrap, and the open work is laid out as a page. */
@media (max-width: 768px) {
  /* Both rows run the full width between the margins: the logo on the left
     with Shuffle and the colour block on the right, then the filters spread
     edge to edge, so AI's right side lines up with the colour block's. */
  .sphere header {
    left: 1rem;
    right: 1rem;
    top: 1rem;
    flex-wrap: wrap;
    row-gap: calc(var(--bar-gap) * var(--fit, 1));
    column-gap: var(--bar-gap);
    justify-content: space-between;
  }

  .sphere #shuffle {
    margin-left: auto;
  }

  /* The bar's buttons join the header's own rows, so they can wrap. */
  .sphere header .bar {
    display: contents;
  }

  /* Still three gaps after the logo. */
  .sphere header img.icon {
    margin-right: calc(2 * var(--bar-gap));
  }

  /* The filters take a row of their own, always one line, spread edge to
     edge. If they would not fit (a narrow phone, or large text set on the
     phone), site.js scales the whole nav down together (--fit on the body)
     until they do: every button, the logo, the colour block and the corner
     text, so they all stay one size. */
  .sphere {
    --h: calc(var(--bar-h) * var(--fit, 1));
  }

  .sphere header img.icon,
  .sphere #shuffle,
  .sphere .filter-button {
    height: var(--h);
  }

  .sphere #colorblock {
    width: var(--h);
    height: var(--h);
  }
  .sphere header .filters {
    flex-basis: 100%;
    flex-wrap: nowrap;
    /* Never wider than the screen, however long the buttons, so an
       overflow shows and site.js can shrink them to fit. */
    min-width: 0;
    justify-content: space-between;
    margin-left: 0;
  }

  /* Slightly tighter buttons and counts, identical to the archive's. */
  .sphere #shuffle,
  .sphere .filter-button {
    padding: 0 calc(0.25rem * var(--fit, 1));
    font-size: calc(0.9rem * var(--fit, 1));
    white-space: nowrap;
  }

  .sphere .filter-button .filter-count {
    font-size: calc(0.6rem * var(--fit, 1));
  }

  /* The corners scale with the nav (--fit), so they stay its size. */
  .sphere #hint,
  .sphere #where {
    bottom: 1rem;
    height: var(--h);
    font-size: calc(0.9rem * var(--fit, 1));
  }

  .sphere #hint {
    left: 1rem;
  }

  .sphere #where {
    right: 1rem;
  }

  /* Smaller, and a long title wraps onto two lines instead of running off a
     sphere that is only a phone wide. */
  .sphere .title {
    font-size: 0.95rem;
    white-space: normal;
    text-align: center;
    width: max-content;
    max-width: 12em;
  }

  .sphere .title.laid {
    text-align: left;
  }

  /* The open work is laid out as a page: its title lifts out of the sphere to
     sit under the nav, and the panel fills the space from there to the footer
     (top and bottom are set by the script). The picture comes first, at
     the full width, up to 60% of the panel's height; the text follows, and
     if it runs past the footer (INFO's bio) the panel scrolls. Before, the
     text kept its height and the picture got what was left, which shrank
     INFO's portrait to almost nothing. */
  .sphere #panel {
    width: calc(100vw - 2rem);
    flex-direction: column;
    gap: 1rem;
    overflow-y: auto;
    touch-action: pan-y;
  }

  .sphere #panel img {
    flex: 0 0 auto;
    width: 100%;
    height: auto;
    max-width: 100%;
    max-height: 60%;
    object-fit: contain;
    object-position: left top;
  }

  .sphere #panel .txt {
    flex: 0 0 auto;
    max-width: none;
  }

}


/* ==========================================================================
   3. GRID PAGES: BASE
   The archive, auto_NS and the project pages. Each is a .container holding
   a .grid; on the archive and auto_NS, packery lays out the .grid-items,
   with the .stamp (the nav or the essay) held in place above them.

   Pages hang off the window's left edge, as the homepage does, not a
   centred column: content is 2rem in (1rem on phones). On very wide screens
   it stops at the grid's max-width, with the extra space on the right.
   ========================================================================== */

html:has(body.page) {
  font-size: 16px;
  line-height: 1.15;
  -webkit-text-size-adjust: 100%;
  /* Reserve the scrollbar's gutter whether or not it is showing, so a filter
     that leaves too few items to scroll does not slide the page sideways. */
  scrollbar-gutter: stable;
}

body.page {
  margin: 0;
  background-color: var(--page);
  overflow-x: hidden;
  transition: opacity 0.25s ease;
}

/* Held hidden until fonts, images and the first layout are done (site.js),
   so there is no font flash or reflow. */
body.page.loading {
  opacity: 0;
}

.page p {
  margin: 0.1875rem 0;
  font-family: var(--font);
  font-weight: 400;
  font-size: 0.9rem;
  line-height: 1.5;
  clear: both;
  color: #1a1a1a;
}

.page h1 {
  float: left;
  clear: both;
  margin: 1.8rem 0 -0.25rem 0;
  padding: 0;
  font-family: var(--font);
  font-weight: 700;
  font-size: 1.3rem;
  color: black;
}

.page a {
  text-decoration: none;
  color: orange;
}

.page img {
  border-style: none;
  width: 100%;
}

.page video {
  display: block;
  margin-top: 0.25rem;
  max-width: 102.75rem;
  width: 100%;
  height: auto;
}

.page .subtitle {
  font-style: italic;
}

.container {
  display: flex;
  justify-content: flex-start;
  margin: 0;
  padding: 0;
}

.grid {
  position: relative;
  width: 100%;
  max-width: 102.75rem;
  padding: 1.25rem;
  margin-top: 5vh;
}

.grid::after {
  content: "";
  display: block;
  clear: both;
}

.stamp {
  position: absolute;
  top: 0;
  left: 0;
}

/* Packery lays out the grid items; a filter hides the ones it leaves out. */
.grid-item-content {
  position: relative;
}

.hideMe {
  display: none !important;
}


/* ==========================================================================
   4. PROJECT PAGES
   The year top left and the category top right, on the nav's line; then the
   title, the text and the images, 2rem in (1rem on phones). auto_NS's essay
   is laid out the same way.

   Rhythm, however the markup nests: 0.75rem between paragraphs, 1.5rem
   between text and a run of images or videos (above and below), 0.5rem
   between the images in a run. Vertical margins between the text and image
   blocks collapse, so the larger gap is the one that shows.
   ========================================================================== */

.grid:has(> .stamp-pp) {
  margin-top: 0;
}

.stamp-pp {
  width: 100%;
  max-width: 102.75rem;
  padding: 3.4rem 2rem 1.25rem;
}

/* A project page is one column, 64rem at most (plus the 2rem margins), so on
   a large screen the images and videos stay a comfortable size and the text
   stays readable. Everything in it fills it, so every edge lines up; the
   category sits on its right edge. auto_NS keeps the full width, which its
   thumbs are laid out across. */
.project .stamp-pp {
  max-width: calc(64rem + 4rem);
}

.stamp-pp::after {
  content: "";
  display: block;
  clear: both;
}

.stamp-pp img {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
}

.stamp-pp p.year,
.stamp-pp p.category {
  position: absolute;
  top: 2rem;
  margin: 0;
  z-index: 3;
  font-size: 0.8rem;
}

.stamp-pp p.year {
  left: 2rem;
  color: black;
}

.stamp-pp p.category {
  right: 2rem;
}

.projectText {
  position: relative;
  float: left;
  width: 100%;
  margin: 1.8rem 0;
}

/* Text boxes nested inside the first one (Nike and others) lose their own
   float and margins, which is what made the gaps uneven. */
.stamp-pp .projectText .projectText {
  float: none;
  width: auto;
  margin: 0;
}

.stamp-pp .projectText p {
  margin: 0 0 0.75rem;
}

.projectText a {
  text-decoration: underline;
}

.projectLocation p::before {
  content: "📍";
  margin-right: 4px;
}

.stamp-pp .projectImage {
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}

.projectImage img {
  display: block;
  width: 100%;
  height: auto;
  padding: 0;
}

.stamp-pp .projectImage > img,
.stamp-pp .projectImage > video,
.stamp-pp .projectImage > iframe {
  margin-top: 0;
  margin-bottom: 0;
}

.stamp-pp .projectImage > * + * {
  margin-top: 0.5rem !important;
}

/* Two images or videos side by side (Aveda, Coldplay), with the same 0.5rem
   gap as between the images in a run. */
.stamp-pp .projectImage .pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  align-items: start;
}

.stamp-pp .projectImage .pair > img,
.stamp-pp .projectImage .pair > video {
  display: block;
  width: 100% !important;
  max-width: 100% !important;
  height: auto;
  margin: 0 !important;
}

/* A link into the artwork itself, as a button (Heliocene). */
.page a.enter {
  text-decoration: none;
}

.page a.enter p {
  margin-top: 1.5rem;
  text-align: center;
  border: 1px solid orange;
  color: orange;
}

/* The signature under an essay (auto_NS, Heliocene). */
.page p.sign {
  position: relative;
  display: block;
  margin: 25px 0 30px 0;
  text-align: right;
  line-height: 1.7;
  font-size: 0.8rem;
}

@media (max-width: 768px) {
  /* No space under the end of the page: the last image or video, running
     edge to edge, meets the bottom of the screen. */
  .stamp-pp {
    padding: 2.4rem 1rem 0;
  }

  .stamp-pp > :last-child,
  .stamp-pp > :last-child > .projectImage:last-child {
    margin-bottom: 0;
  }

  .stamp-pp p.year,
  .stamp-pp p.category {
    top: 1rem;
  }

  .stamp-pp p.year {
    left: 1rem;
  }

  .stamp-pp p.category {
    right: 1rem;
  }

  /* Images run full-bleed, edge to edge of the phone. */
  .stamp .projectImage > img,
  .stamp .projectImage > video {
    display: block;
    width: 100vw !important;
    max-width: 100vw !important;
    height: auto !important;
    margin-left: calc(50% - 50vw) !important;
    margin-right: calc(50% - 50vw) !important;
  }
}


/* ==========================================================================
   5. THE ARCHIVE
   Each row reads as one line: the year, then a short sentence describing
   the work (.line, written by hand, names in bold and titles in italics),
   after old.jakedowsmith.com. Rows do not open; a click goes to the work
   (data-href) in a new tab. On desktop, hovering a row shows its image
   (data-img, written by tools/archive_thumbs.py) in the #tip card that
   follows the pointer. Rows are divided by horizontal rules only.
   ========================================================================== */

body.archive {
  background-color: orange;
}

/* The nav sits 2rem from the top of the page, not below the grid's 5vh; on
   desktop the rows run the full width of the window between the 2rem
   margins. */
.archive .grid {
  margin-top: 0;
}

/* ---- The nav: the homepage's buttons and spacing (all --bar-h tall,
   --bar-gap apart, three gaps between By Date and the filters), in the
   archive's orange, with no logo. It sits 2rem in and 2rem down, as the
   homepage's does. The stamp is absolutely positioned, so the grid's
   padding does not apply to it; its own padding places it. Its height
   follows what is in it, so the rows start the same distance below the nav
   even if the filters wrap. */
.stamp-archive {
  width: 100%;
  padding: 2rem 2rem 1.5rem;
}

.stamp-archive .bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--bar-gap) calc(3 * var(--bar-gap));
}

.stamp-archive .actions,
.stamp-archive .filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bar-gap);
}

.stamp-archive button {
  display: inline-flex;
  align-items: center;
  height: var(--bar-h);
  margin: 0;
  padding: 0 0.375rem;
  background-color: orange;
  color: black;
  font-family: var(--font);
  font-weight: 700;
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  border: 1px outset ButtonBorder;
}

.stamp-archive button:hover {
  background-color: #ee9a00;
}

.stamp-archive button:active,
.stamp-archive button.btnSelected {
  background-color: #cc8400;
  border: 1px inset ButtonBorder;
}

/* No focus ring after a mouse or touch press, as on the homepage; a keyboard
   user still gets one. */
.stamp-archive button:focus:not(:focus-visible) {
  outline: none;
}

/* Counts sit straight after their label. Translucent black rather than a
   fixed grey, so they stay legible on every shade of orange. */
.stamp-archive .filter-count {
  font-size: 0.7rem;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.5);
}

/* ---- The rows. No inner padding: the year starts on the nav's left edge,
   and the rules run the same width as the text. */
.grid-item.archive {
  width: calc(100% - 4rem);
}

.grid-item-content.archive {
  display: grid;
  grid-template-columns: 5rem minmax(0, 1fr);
  grid-template-rows: 2rem;
  column-gap: 1rem;
  align-items: center;
  width: 100%;
  border-bottom: 1px solid black;
  cursor: pointer;
}

.grid-item-content.archive.nolink {
  cursor: default;
}

.archive p.year {
  grid-column: 1;
  margin: 0;
  font-size: 0.9rem;
  line-height: 1;
  color: black;
}

.archive p.line {
  grid-column: 2;
  margin: 0;
  font-size: 0.9rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.archive p.line b {
  font-weight: 700;
}

/* The hover card. */
#tip {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 1000;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
  border: 1px solid black;
  /* Transparent, so an image with transparency (True Self) shows the
     archive's orange through it. */
  background: transparent;
  will-change: transform, opacity;
}

#tip.on {
  opacity: 1;
}

#tip img {
  display: block;
  width: 14rem;
  height: auto;
}

@media (min-width: 769px) {
  .archive .grid {
    padding-left: 2rem;
    padding-right: 2rem;
    max-width: none;
  }
}

/* Phones: 1rem in and down, as on the homepage; rows run edge to edge with
   their text 1rem in, and a sentence may wrap onto a second line. */
@media (max-width: 768px) {
  .stamp-archive {
    padding: 1rem;
  }

  /* The archive scrolls and the homepage does not, so in a desktop browser
     at phone width the archive's scrollbar would take ~15-20px off the
     right that the homepage never loses. A phone's own scrollbar overlays
     the page and takes nothing, so here it is hidden too (it still
     scrolls). */
  html:has(body.archive) {
    scrollbar-width: none;
    scrollbar-gutter: auto;
  }

  html:has(body.archive)::-webkit-scrollbar {
    display: none;
  }

  /* One gap between the rows, as on the homepage. Shuffle and By Date on
     the right of the first row, By Date's right edge on AI's; the filters spread edge to edge
     below. */
  .stamp-archive .bar {
    row-gap: calc(var(--bar-gap) * var(--fit, 1));
  }

  .stamp-archive .actions {
    margin-left: auto;
  }

  /* Always one line, shrunk to fit if need be, as on the homepage. */
  .stamp-archive .filters {
    flex-basis: 100%;
    flex-wrap: nowrap;
    /* Never wider than the screen, however long the buttons, so an
       overflow shows and site.js can shrink them to fit. */
    min-width: 0;
    justify-content: space-between;
  }

  /* Identical to the homepage's phone buttons, scaled with it (--fit on the
     bar) so that every button stays one size. */
  .stamp-archive .bar {
    --h: calc(var(--bar-h) * var(--fit, 1));
  }

  .stamp-archive button {
    height: var(--h);
    padding: 0 calc(0.25rem * var(--fit, 1));
    font-size: calc(0.9rem * var(--fit, 1));
    white-space: nowrap;
  }

  .stamp-archive .filter-count {
    font-size: calc(0.6rem * var(--fit, 1));
  }

  .grid-item.archive {
    width: 100%;
    margin-left: -1.25rem;
  }

  .grid-item-content.archive {
    grid-template-columns: 3.25rem minmax(0, 1fr);
    grid-template-rows: auto;
    align-items: baseline;
    min-height: 2rem;
    padding: 0.5rem 1rem;
  }

  .archive p.line {
    white-space: normal;
    line-height: 1.35;
  }
}


/* ==========================================================================
   6. AUTO_NS
   The essay, then every #auto_NS post as a small thumb with its caption,
   shuffled on each visit. The columns span the essay's width exactly (the
   script sets --ig-w, --ig-inset and packery's gutter); each size class adds
   its own space under the caption and each thumb a random space above, so
   the columns end and start unevenly. Clicking a thumb opens the post large
   (#igview). The tiles are written by tools/auto_ns_posts.py.
   ========================================================================== */

.autons h1 {
  margin-top: 0.8rem;
}

/* The auto_NS logo above the title. */
.autons .grid-item-icon {
  width: 5.25rem;
  padding-top: 1.25rem;
  margin-left: -0.15rem;
}

.ig {
  display: block;
  width: var(--ig-w, 120px);
  margin: 0 0 0 var(--ig-inset, 0px);
  padding: 0;
  cursor: pointer;
}

.ig img,
.ig video {
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
}

.page .ig p {
  margin: 0.5rem 0 0;
  font-style: italic;
  font-size: 0.75rem;
  line-height: 1.1;
}

.ig.XS { padding-bottom: 0.5rem; }
.ig.S  { padding-bottom: 1.5rem; }
.ig.M  { padding-bottom: 3rem; }
.ig.L  { padding-bottom: 5rem; }

/* ---- The open post, as the homepage opens a work: the picture keeps its own
   proportions, bounded by the room it has, with the text beside it. */
#igview {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(243, 243, 243, 0.96);
  font-family: var(--font);
  opacity: 0;
  transition: opacity 0.28s ease;
}

#igview[hidden] {
  display: none;
}

#igview.on {
  opacity: 1;
}

#igview .ig-panel {
  width: min(78rem, 90vw);
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
  transform: translateY(0.5rem);
  transition: transform 0.28s ease;
}

#igview.on .ig-panel {
  transform: translateY(0);
}

#igview .ig-media {
  flex: 0 1 auto;
  max-width: 60%;
  line-height: 0;
}

#igview .ig-media.multi {
  cursor: e-resize;
}

#igview .ig-media img,
#igview .ig-media video {
  display: block;
  max-width: 100%;
  max-height: 80vh;
  width: auto;
  height: auto;
  margin: 0;
}

#igview .ig-txt {
  flex: 1;
  max-width: 34rem;
  font-size: 0.8rem;
  line-height: 1.75;
  user-select: text;
}

#igview .ig-date,
#igview .ig-count {
  display: block;
  opacity: 0.45;
}

#igview .ig-cap {
  margin: 0.4rem 0 0.75rem;
  font-style: italic;
}

/* [ close ], as on the homepage: a button that looks like text. */
#igview .ig-close {
  display: block;
  margin: 1rem 0 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  opacity: 0.45;
  cursor: pointer;
}

#igview .ig-close:hover {
  opacity: 0.9;
}

@media (max-width: 768px) {
  #igview {
    align-items: flex-start;
    overflow-y: auto;
  }

  #igview .ig-panel {
    width: calc(100vw - 2rem);
    flex-direction: column;
    gap: 1rem;
    padding: 1rem 0;
  }

  #igview .ig-media {
    max-width: 100%;
  }

  #igview .ig-media img,
  #igview .ig-media video {
    max-height: 70vh;
  }
}


/* ==========================================================================
   7. I BELIEVE YOU INTO BEING
   A world of its own: the poem on the right over a pale green, the video
   vignettes on the left, the two split by a draggable gutter (Split.js).
   Hovering a figure in the poem plays its vignette behind. The page also
   loads normalize.css, before this file. Not for phones: #block covers it.
   ========================================================================== */

html:has(body.ibyib) {
  height: 100%;
  line-height: 1.15;
  -webkit-text-size-adjust: 100%;
}

body.ibyib {
  height: 100%;
  padding: 0;
  background-color: #c2c8c2;
}

.ibyib img {
  border-style: none;
}

.ibyib a {
  margin: 0 3px;
  color: black;
  text-decoration: underline;
  letter-spacing: 2px;
}

/* A link out, marked with a small arrow. */
.ibyib a.blank::after {
  content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);
  position: relative;
  bottom: 3px;
  left: 2px;
}

/* The words in the about paragraph that show a still on hover. */
.ibyib .tooltip {
  position: relative;
  text-decoration: none;
}

.ibyib .tooltip span {
  display: none;
}

.ibyib .tooltip:hover span {
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  margin-top: 24px;
  margin-left: -162px;
  overflow: hidden;
}

.ibyib .tooltip span img {
  display: block;
  position: fixed;
  z-index: 1000;
}

.ibyib .landscape {
  width: 320px;
  height: 180px;
}

.ibyib .portrait {
  width: 270px;
  height: 320px;
}

/* ---- The two panes and the gutter between them. */
.ibyib .split {
  overflow-y: auto;
  overflow-x: hidden;
}

.ibyib .split.split-horizontal,
.ibyib .gutter.gutter-horizontal {
  height: 100%;
  float: left;
}

.ibyib #a,
.ibyib #b {
  bottom: 0;
}

.ibyib #a {
  background: none;
}

.ibyib #b {
  background: #d7e0d8;
}

.ibyib #b::-webkit-scrollbar {
  width: 10px;
  background-color: #d7e0d8;
}

.ibyib #b::-webkit-scrollbar-track {
  background-color: #d7e0d8;
}

.ibyib #b::-webkit-scrollbar-thumb {
  background-color: #c2c8c2;
}

.ibyib .gutter {
  background-color: transparent;
  background-repeat: repeat;
  background-position: 50%;
}

.ibyib .gutter.gutter-horizontal {
  cursor: col-resize;
  background-color: #e5e5f7;
  opacity: 0.8;
  background-image: radial-gradient(black 0.8px, #e5e5f7 0.8px);
  background-size: 3px 3px;
}

/* ---- The vignettes: one full-window video per figure, shown on hover. */
.ibyib .hideBG {
  display: none;
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: -2;
}

.ibyib video {
  object-fit: cover;
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
}

/* The playing figure's number, bottom left, and the sound toggle, bottom
   right. */
.ibyib .IBYIB_title {
  position: fixed;
  bottom: 5px;
  left: 22px;
  display: block;
  color: white;
  z-index: -1;
}

.ibyib .IBYIB_title p {
  letter-spacing: 5px;
  font-family: "Times New Roman", Times, serif;
  font-size: 0.8em;
}

.ibyib .mute {
  position: fixed;
  bottom: 5px;
  right: 22px;
  display: block;
  color: black;
  z-index: 1;
  cursor: pointer;
}

.ibyib .mute p {
  letter-spacing: 5px;
  font-family: var(--font);
  font-size: 12px;
}

.ibyib .mute .on {
  margin-right: 7px;
}

/* ---- The poem. */
.ibyib .IBYIB_container {
  display: block;
  padding: 3vh 3vw 0 3vw;
  z-index: 1;
}

.ibyib h1.IBYIB {
  font-family: "Markazi Text", serif;
  letter-spacing: 1px;
  font-size: 2em;
  font-weight: 100;
  padding: 14px 0 30px 0;
}

.ibyib .IBYIB_about {
  line-height: 1.5;
  font-family: var(--font);
  font-size: 13px;
  padding-bottom: 28px;
}

.ibyib a.venue {
  display: inline-block;
  margin-right: 9px;
}

.ibyib .tooltip.tight {
  margin-right: -9px;
}

.ibyib .skew {
  display: inline-block;
  margin: 0 1px;
  transform: skewX(-8deg);
}

.ibyib .IBYIB_stanza {
  width: 80vw;
  padding-right: 5vh;
}

.ibyib p.IBYIB_doubleSpace {
  line-height: 2;
  font-family: "Markazi Text", serif;
  font-size: 1.5em;
  padding-bottom: 19px;
}

/* The figure being played. */
.ibyib .hover {
  background: radial-gradient(ellipse at center, #afe575, #d7e0d8);
  cursor: pointer;
}

/* The profile-line marks between the stanzas. */
.ibyib .noType {
  font-family: "Times New Roman", Times, serif;
  margin-left: 30px;
  font-size: 16px;
}

.ibyib .moveUp {
  margin-top: -25px;
}

.ibyib .moveLeft {
  margin-left: 37px;
}

.ibyib p.date span {
  margin-left: 1px;
}

.ibyib p.date {
  position: relative;
  left: 33vw;
  text-align: left;
  font-size: 13px;
  padding: 37px 0 120px 0;
  letter-spacing: 2px;
  line-height: 2;
  font-family: var(--font);
}

/* ---- Phones get a note instead. */
.ibyib #block {
  display: block;
  position: absolute;
  height: 100vh;
  width: 100vw;
  background-color: #000;
  z-index: 999;
}

.ibyib #block p {
  color: white;
  font-family: var(--font);
  padding: 14px 21px;
}

@media (min-width: 769px) {
  .ibyib #block {
    display: none;
  }
}
