@layer reset, tokens, base, layout, components, utilities;

/* ---------------------------------------------------------------- reset -- */

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }
  html { -webkit-text-size-adjust: none; text-size-adjust: none; interpolate-size: allow-keywords; }
  img, svg { display: block; max-width: 100%; }
  input, button, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
  button { cursor: pointer; }
  ul[role="list"] { list-style: none; padding: 0; }
}

/* --------------------------------------------------------------- tokens -- */

@layer tokens {
  :root {
    color-scheme: light dark;

    --accent-h: 28;
    --accent: oklch(68% 0.19 var(--accent-h));
    --accent-strong: oklch(from var(--accent) calc(l - 0.08) c h);
    --on-accent: oklch(99% 0.01 var(--accent-h));
    --accent-soft: color-mix(in oklch, var(--accent) 16%, transparent);

    --bg: light-dark(oklch(97.5% 0.006 80), oklch(15.5% 0.008 260));
    --surface: light-dark(oklch(100% 0 0), oklch(20% 0.01 260));
    --surface-2: light-dark(oklch(94.5% 0.008 80), oklch(25% 0.012 260));
    --text: light-dark(oklch(23% 0.015 260), oklch(94% 0.008 80));
    --muted: light-dark(oklch(50% 0.015 260), oklch(70% 0.012 260));
    --line: color-mix(in oklch, var(--text) 11%, transparent);
    --line-strong: color-mix(in oklch, var(--text) 22%, transparent);
    --ok: light-dark(oklch(52% 0.13 150), oklch(78% 0.14 150));
    --warn: light-dark(oklch(55% 0.14 60), oklch(80% 0.13 75));

    --font: "Inter Variable", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;

    --radius-s: 0.375rem;
    --radius: 0.625rem;
    --radius-l: 1rem;
    --gap: 0.375rem;
    --row-height: 220px;
    --masthead: 4rem;
    --panel-width: 18.5rem;
    --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
    --shadow: 0 1px 2px oklch(0% 0 0 / 0.08), 0 8px 24px -8px oklch(0% 0 0 / 0.2);
  }
}

/* ----------------------------------------------------------------- base -- */

@layer base {
  html {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
    font-size: 100%;
    line-height: 1.5;
    font-feature-settings: "cv11", "ss01";
    -webkit-font-smoothing: antialiased;
    scrollbar-gutter: stable;
    accent-color: var(--accent);
  }

  body { min-height: 100dvh; }
  h1, h2, h3 { line-height: 1.2; text-wrap: balance; }
  p { text-wrap: pretty; }

  a { color: inherit; text-decoration-color: var(--line-strong); text-underline-offset: 0.2em; }
  a:hover { text-decoration-color: currentColor; }

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

  .icon {
    inline-size: 1.25em;
    block-size: 1.25em;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  kbd {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--line-strong);
    border-block-end-width: 2px;
    border-radius: var(--radius-s);
    color: var(--muted);
  }

  select {
    appearance: none;
    padding: 0.4rem 2rem 0.4rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background:
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E")
      no-repeat right 0.5rem center / 1rem,
      var(--surface);
    field-sizing: content;
  }

  /* Customisable <select> where supported: the picker matches the rest of the UI. */
  @supports (appearance: base-select) {
    select, ::picker(select) { appearance: base-select; }
    select::picker-icon { display: none; }
    ::picker(select) {
      margin-block: 0.25rem;
      padding: 0.25rem;
      border: 1px solid var(--line);
      border-radius: var(--radius);
      background: var(--surface);
      box-shadow: var(--shadow);
      opacity: 0;
      translate: 0 -0.25rem;
      transition: opacity 0.15s, translate 0.15s var(--ease-out), overlay 0.15s allow-discrete, display 0.15s allow-discrete;
    }
    ::picker(select):popover-open { opacity: 1; translate: 0; }
    @starting-style { ::picker(select):popover-open { opacity: 0; translate: 0 -0.25rem; } }
    option {
      padding: 0.35rem 0.6rem;
      border-radius: var(--radius-s);
      &:hover, &:focus-visible { background: var(--surface-2); }
      &:checked { color: var(--accent-strong); font-weight: 600; }
      &::checkmark { display: none; }
      &:disabled { color: var(--muted); opacity: 0.5; }
    }
  }

  input[type="range"] {
    --value: 0.5;
    appearance: none;
    block-size: 1.25rem;
    background: transparent;
    cursor: pointer;

    &::-webkit-slider-runnable-track { block-size: 4px; border-radius: 99px; background: linear-gradient(to right, var(--accent) calc(var(--value) * 100%), var(--line-strong) 0); }
    &::-moz-range-track { block-size: 4px; border-radius: 99px; background: var(--line-strong); }
    &::-moz-range-progress { block-size: 4px; border-radius: 99px; background: var(--accent); }
    &::-webkit-slider-thumb { appearance: none; margin-block-start: -6px; inline-size: 16px; block-size: 16px; border-radius: 50%; background: var(--surface); border: 2px solid var(--accent); box-shadow: var(--shadow); }
    &::-moz-range-thumb { inline-size: 12px; block-size: 12px; border-radius: 50%; background: var(--surface); border: 2px solid var(--accent); }
  }
}

/* --------------------------------------------------------------- layout -- */

@layer layout {
  .masthead {
    position: sticky;
    inset-block-start: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 1rem;
    block-size: var(--masthead);
    padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
    background: color-mix(in oklch, var(--bg) 82%, transparent);
    backdrop-filter: blur(16px) saturate(1.4);
    border-block-end: 1px solid transparent;

    /* A hairline and shadow appear as soon as the page scrolls under it. */
    @supports (animation-timeline: scroll()) {
      animation: masthead-lift linear both;
      animation-timeline: scroll();
      animation-range: 0 3rem;
    }

    /* Indeterminate progress while a query is in flight. */
    &::after {
      content: "";
      position: absolute;
      inset: auto 0 -1px;
      block-size: 2px;
      background: linear-gradient(90deg, transparent, var(--accent), transparent) no-repeat;
      background-size: 40% 100%;
      opacity: 0;
      transition: opacity 0.2s;
    }
    photo-browser[loading] &::after {
      opacity: 1;
      transition-delay: 0.15s;
      animation: progress 1s linear infinite;
    }
  }

  @keyframes masthead-lift {
    to { border-block-end-color: var(--line); box-shadow: 0 6px 20px -12px oklch(0% 0 0 / 0.35); }
  }
  @keyframes progress {
    from { background-position: -60% 0; }
    to { background-position: 160% 0; }
  }

  .layout {
    display: grid;
    grid-template-columns: 1fr;
    align-items: start;
    padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
    gap: 1.5rem;

    @media (width >= 64rem) {
      grid-template-columns: var(--panel-width) minmax(0, 1fr);
    }
  }

  main {
    min-inline-size: 0;
    padding-block-end: 4rem;
  }
}

/* ----------------------------------------------------------- components -- */

@layer components {
  /* --- masthead ---------------------------------------------------------- */

  .brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    text-decoration: none;
    font-weight: 500;
    letter-spacing: -0.01em;
    white-space: nowrap;

    b { font-weight: 750; }
    @media (width < 40rem) { > span:last-child { display: none; } }
  }

  .brand-mark {
    display: grid;
    place-items: center;
    inline-size: 2rem;
    block-size: 2rem;
    border-radius: 0.55rem;
    background: linear-gradient(135deg, var(--accent), oklch(from var(--accent) l c calc(h - 40)));
    color: var(--on-accent);
    font-weight: 800;
    font-size: 0.95rem;
    letter-spacing: -0.04em;
  }

  .search {
    flex: 1;
    max-inline-size: 44rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-inline: 0.85rem 0.3rem;
    block-size: 2.625rem;
    border: 1px solid var(--line);
    border-radius: 99px;
    background: var(--surface);
    transition: border-color 0.15s, box-shadow 0.15s;

    &:focus-within {
      border-color: var(--accent);
      box-shadow: 0 0 0 4px var(--accent-soft);
    }
    > .icon { color: var(--muted); }

    input {
      flex: 1;
      min-inline-size: 0;
      border: 0;
      background: none;
      outline: none;
      &::placeholder { color: var(--muted); }
    }
    /* The shortcut hint only matters until you're in the box. */
    &:focus-within kbd, &:has(input:not(:placeholder-shown)) kbd { display: none; }

    select {
      border: 0;
      border-radius: 99px;
      background-color: var(--surface-2);
      font-size: 0.875rem;
      block-size: 2rem;
      padding-block: 0;
    }
    @media (width < 40rem) {
      kbd, select { display: none; }
    }
  }

  .filters-toggle.button {
    margin-inline-start: auto;
    @media (width >= 64rem) { display: none; }
  }

  /* --- buttons ----------------------------------------------------------- */

  .button, .small-button {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: 99px;
    background: var(--surface);
    font-size: 0.875rem;
    font-weight: 550;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s, border-color 0.15s, scale 0.1s;

    &:hover { background: var(--surface-2); border-color: var(--line-strong); }
    &:active { scale: 0.97; }
    &.primary {
      background: var(--accent);
      border-color: transparent;
      color: var(--on-accent);
      &:hover { background: var(--accent-strong); }
    }
  }

  .small-button { padding: 0.25rem 0.6rem; font-size: 0.8125rem; }

  .icon-button {
    display: inline-grid;
    place-items: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--muted);
    transition: background-color 0.15s, color 0.15s;
    &:hover { background: var(--surface-2); color: var(--text); }
  }

  /* --- filter panel ------------------------------------------------------ */

  #filters-panel {
    /* Narrow screens: a light-dismiss popover sliding in from the side. */
    position: fixed;
    inset: 0 auto 0 0;
    inline-size: min(22rem, 90vw);
    block-size: 100dvh;
    max-block-size: none;
    margin: 0;
    padding: 0;
    border: 0;
    border-inline-end: 1px solid var(--line);
    background: var(--bg);
    color: var(--text);
    overflow: auto;
    overscroll-behavior: contain;
    translate: -100% 0;
    transition: translate 0.3s var(--ease-out), overlay 0.3s allow-discrete, display 0.3s allow-discrete;

    &:popover-open {
      translate: 0 0;
      @starting-style { translate: -100% 0; }
    }
    &::backdrop {
      background: oklch(0% 0 0 / 0);
      transition: background-color 0.3s, overlay 0.3s allow-discrete, display 0.3s allow-discrete;
    }
    &:popover-open::backdrop {
      background: oklch(0% 0 0 / 0.4);
      @starting-style { background: oklch(0% 0 0 / 0); }
    }

    form { padding: 1rem 1.25rem 1.5rem; }

    /* Wide screens: always there, as a sticky sidebar. */
    @media (width >= 64rem) {
      display: block;
      position: sticky;
      inset: var(--masthead) auto auto;
      inline-size: auto;
      block-size: calc(100dvh - var(--masthead));
      translate: none;
      transition: none;
      border: 0;
      background: none;
      scrollbar-width: thin;
      scrollbar-color: var(--line-strong) transparent;

      form { padding: 0.75rem 0.5rem 3rem 0; }
      .panel-head, .panel-done { display: none; }
    }
  }

  .panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-block-end: 0.5rem;
    h2 { font-size: 1.125rem; }
  }

  .panel-done {
    position: sticky;
    inset-block-end: 0;
    inline-size: 100%;
    justify-content: center;
    margin-block-start: 1rem;
    padding-block: 0.75rem;
    box-shadow: 0 -12px 24px 4px var(--bg);
  }

  .group {
    border-block-end: 1px solid var(--line);

    summary {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      padding-block: 0.8rem;
      font-size: 0.8125rem;
      font-weight: 650;
      letter-spacing: 0.04em;
      text-transform: uppercase;
      color: var(--muted);
      cursor: pointer;
      list-style: none;
      user-select: none;
      &::-webkit-details-marker { display: none; }
      &:hover { color: var(--text); }

      /* Chevron that turns as the group opens. */
      &::after {
        content: "";
        order: 2;
        margin-inline-start: auto;
        inline-size: 0.45rem;
        block-size: 0.45rem;
        border: solid currentColor;
        border-width: 0 1.5px 1.5px 0;
        rotate: 45deg;
        translate: 0 -0.15rem;
        transition: rotate 0.2s var(--ease-out), translate 0.2s var(--ease-out);
      }
    }
    &[open] summary::after { rotate: 225deg; translate: 0 0.1rem; }

    /* A dot marks a collapsed group that's still filtering. */
    &:not([open]):has(:checked:not([value=""])) summary::before {
      content: "";
      order: 1;
      inline-size: 0.4rem;
      block-size: 0.4rem;
      border-radius: 50%;
      background: var(--accent);
    }

    /* Animate open and closed (interpolate-size lets height reach `auto`). */
    &::details-content {
      block-size: 0;
      overflow: clip;
      transition: block-size 0.25s var(--ease-out), content-visibility 0.25s allow-discrete;
    }
    &[open]::details-content { block-size: auto; }
    > :last-child { margin-block-end: 1rem; }
  }

  facet-list {
    display: grid;
    gap: 0.5rem;

    .facet-search {
      inline-size: 100%;
      padding: 0.35rem 0.7rem;
      border: 1px solid var(--line);
      border-radius: var(--radius);
      background: var(--surface);
      font-size: 0.875rem;
      &:focus { outline: none; border-color: var(--accent); }
    }

    .more {
      justify-self: start;
      padding: 0;
      border: 0;
      background: none;
      color: var(--accent-strong);
      font-size: 0.8125rem;
      font-weight: 600;
      &:hover { text-decoration: underline; }
    }
    .none { color: var(--muted); font-size: 0.875rem; }
  }

  /* One option: a real checkbox or radio, restyled per `data-kind`. */
  .options {
    --option-pad: 0.3rem;

    .option {
      position: relative;
      display: flex;
      align-items: center;
      gap: 0.55rem;
      cursor: pointer;
      font-size: 0.875rem;
      transition: opacity 0.2s;

      &[data-empty]:not(:has(:checked)) { opacity: 0.45; }
    }
    .label { flex: 1; min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .count {
      font-family: var(--font-mono);
      font-size: 0.75rem;
      color: var(--muted);
      font-variant-numeric: tabular-nums;
    }

    /* Plain list: custom checkbox, and a faint bar showing each option's share. */
    &[data-kind="list"] {
      display: grid;
      gap: 1px;

      .option {
        padding: var(--option-pad) 0.4rem;
        border-radius: var(--radius-s);
        /* A hairline under each option shows its share of the largest. */
        &::before {
          content: "";
          position: absolute;
          inset: auto auto 0 2.0rem;
          inline-size: calc(var(--share, 0) * (100% - 2.4rem));
          block-size: 2px;
          border-radius: 2px;
          background: var(--line);
          transition: inline-size 0.4s var(--ease-out);
        }
        &:has(:checked)::before { background: color-mix(in oklch, var(--accent) 45%, transparent); }
        &:hover { background: var(--surface-2); }
        &:has(:checked) .label { font-weight: 600; }
      }

      input {
        appearance: none;
        display: grid;
        place-content: center;
        flex: none;
        inline-size: 1rem;
        block-size: 1rem;
        margin: 0;
        border: 1.5px solid var(--line-strong);
        border-radius: 0.3rem;
        background: var(--surface);
        transition: background-color 0.12s, border-color 0.12s;

        &::after {
          content: "";
          inline-size: 0.5rem;
          block-size: 0.3rem;
          border: solid var(--on-accent);
          border-width: 0 0 2px 2px;
          rotate: -45deg;
          translate: 0 -0.05rem;
          scale: 0;
          transition: scale 0.15s var(--ease-out);
        }
        &:checked { background: var(--accent); border-color: var(--accent); }
        &:checked::after { scale: 1; }
      }
    }

    /* Chips: the whole pill is the control. */
    &[data-kind="chips"] {
      display: flex;
      flex-wrap: wrap;
      gap: 0.35rem;

      .option {
        gap: 0.35rem;
        padding: 0.25rem 0.65rem;
        border: 1px solid var(--line);
        border-radius: 99px;
        background: var(--surface);
        font-size: 0.8125rem;
        transition: background-color 0.15s, border-color 0.15s, color 0.15s, opacity 0.2s;
        &:hover { border-color: var(--line-strong); }
        &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
        &:has(:checked) {
          background: var(--accent);
          border-color: var(--accent);
          color: var(--on-accent);
          .count { color: inherit; opacity: 0.8; }
        }
      }
      .label { flex: none; }
      input { position: absolute; opacity: 0; pointer-events: none; }
    }

    /* Histogram: one column per year, bar height is that year's share. */
    &[data-kind="histogram"] {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(1.85rem, 1fr));
      gap: 0.2rem 0.15rem;

      .option {
        flex-direction: column;
        justify-content: end;
        gap: 0.2rem;
        block-size: 4.75rem;
        padding: 0;

        &::before {
          content: "";
          inline-size: 100%;
          block-size: max(3px, calc(var(--share, 0) * 3.4rem));
          border-radius: 3px 3px 1px 1px;
          background: var(--line-strong);
          transition: block-size 0.4s var(--ease-out), background-color 0.15s;
        }
        &:hover::before { background: color-mix(in oklch, var(--accent) 50%, var(--line-strong)); }
        &:has(:checked)::before { background: var(--accent); }
        &:has(:checked) .label { color: var(--text); font-weight: 700; }
        &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
      }
      .label { flex: none; font-size: 0.6875rem; color: var(--muted); font-variant-numeric: tabular-nums; }
      .count { display: none; }
      input { position: absolute; opacity: 0; pointer-events: none; }
    }
  }

  .slider {
    display: grid;
    gap: 0.25rem;
    margin-block-start: 0.85rem;
    font-size: 0.8125rem;
    color: var(--muted);
    > span { display: flex; justify-content: space-between; }
    output { font-family: var(--font-mono); font-size: 0.75rem; color: var(--text); }
  }

  .switch {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-block-end: 0.75rem;
    font-size: 0.875rem;
    font-weight: 550;
    cursor: pointer;

    .count { margin-inline-start: auto; font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); }

    input {
      appearance: none;
      position: relative;
      flex: none;
      inline-size: 2.1rem;
      block-size: 1.2rem;
      margin: 0;
      border-radius: 99px;
      background: var(--line-strong);
      transition: background-color 0.2s;

      &::before {
        content: "";
        position: absolute;
        inset: 0.15rem auto 0.15rem 0.15rem;
        aspect-ratio: 1;
        border-radius: 50%;
        background: white;
        box-shadow: 0 1px 2px oklch(0% 0 0 / 0.3);
        transition: translate 0.2s var(--ease-out);
      }
      &:checked { background: var(--accent); }
      &:checked::before { translate: 0.9rem 0; }
    }
  }

  /* --- results toolbar --------------------------------------------------- */

  .toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1rem;
    padding-block: 1rem 0.85rem;
  }

  .total {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    output { font-variant-numeric: tabular-nums; }
    span { color: var(--muted); font-weight: 450; }
  }

  .controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-inline-start: auto;

    select { font-size: 0.875rem; }
    .size {
      display: flex;
      align-items: center;
      gap: 0.4rem;
      color: var(--muted);
      input { inline-size: 6rem; }
      @media (width < 40rem) { display: none; }
    }

    /* Only offer a reshuffle while shuffled — no script needed to decide. */
    [data-reshuffle] { display: none; }
    &:has(option[value="shuffle"]:checked) [data-reshuffle] { display: inline-grid; }
  }

  active-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    flex-basis: 100%;

    ul { display: contents; }

    .chip {
      display: inline-flex;
      align-items: center;
      gap: 0.3rem;
      padding: 0.2rem 0.35rem 0.2rem 0.7rem;
      border: 1px solid color-mix(in oklch, var(--accent) 35%, transparent);
      border-radius: 99px;
      background: var(--accent-soft);
      font-size: 0.8125rem;
      font-weight: 550;
      transition: background-color 0.15s;
      .icon { inline-size: 1rem; block-size: 1rem; opacity: 0.6; }
      &:hover { background: color-mix(in oklch, var(--accent) 28%, transparent); .icon { opacity: 1; } }
    }

    .clear {
      padding: 0.2rem 0.5rem;
      border: 0;
      background: none;
      color: var(--muted);
      font-size: 0.8125rem;
      &:hover { color: var(--text); text-decoration: underline; }
    }

    li { view-transition-class: chip; }
  }

  /* --- photo grid -------------------------------------------------------- */

  photo-grid {
    display: block;
    view-transition-name: results;

    .grid {
      display: flex;
      flex-wrap: wrap;
      gap: var(--gap);

      /* Soaks up the leftover width so the last row isn't stretched. */
      &::after { content: ""; flex-grow: 1000000; }
    }

    .status:empty { display: none; }
    .sentinel { block-size: 1px; }

    .end, .error, .empty {
      padding-block: 2.5rem;
      text-align: center;
      color: var(--muted);
    }
    .empty {
      display: grid;
      justify-items: center;
      gap: 0.75rem;
      padding-block: 5rem;
      .icon { inline-size: 3rem; block-size: 3rem; stroke-width: 1.25; opacity: 0.5; }
      strong { color: var(--text); }
    }
  }

  @scope (photo-grid) {
    .card {
      --ratio: calc(var(--w) / var(--h));
      position: relative;
      /* Justified rows: grow in proportion to aspect ratio from a common height. */
      flex: calc(var(--ratio) * 1000) 1 calc(var(--ratio) * var(--row-height));
      aspect-ratio: var(--w) / var(--h);
      max-block-size: calc(var(--row-height) * 2.2);
      overflow: clip;
      border-radius: var(--radius-s);
      background: var(--surface-2);
      container-type: inline-size;
      content-visibility: auto;
      color: white;
      text-decoration: none;
      outline-offset: 3px;

      img {
        inline-size: 100%;
        block-size: 100%;
        object-fit: cover;
        opacity: 0;
        scale: 1.015;
        transition: opacity 0.35s ease, scale 0.6s var(--ease-out);
        &.loaded { opacity: 1; scale: 1; }
        &.broken { opacity: 0; }
      }
      &:hover img.loaded { scale: 1.03; }

      .meta {
        position: absolute;
        inset: auto 0 0;
        display: grid;
        padding: 2.5rem 0.7rem 0.55rem;
        background: linear-gradient(transparent, oklch(0% 0 0 / 0.72));
        opacity: 0;
        translate: 0 0.35rem;
        transition: opacity 0.2s, translate 0.25s var(--ease-out);
        pointer-events: none;
      }
      .title {
        font-size: 0.8125rem;
        font-weight: 600;
        line-height: 1.3;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      .byline { font-size: 0.75rem; opacity: 0.8; }

      &:is(:hover, :focus-visible) .meta { opacity: 1; translate: 0; }
      @media (hover: none) { .meta { display: none; } }
      /* Tiny thumbnails have no room for words. */
      @container (width < 9rem) { .meta { display: none; } }

      .badge {
        position: absolute;
        inset: 0.4rem 0.4rem auto auto;
        display: grid;
        place-items: center;
        inline-size: 1.35rem;
        block-size: 1.35rem;
        border-radius: 50%;
        background: oklch(0% 0 0 / 0.55);
        backdrop-filter: blur(6px);
        font-size: 0.75rem;
        font-weight: 700;
        opacity: 0;
        transition: opacity 0.2s;
      }
      &:hover .badge { opacity: 1; }
    }
  }

  /* --- viewer ------------------------------------------------------------ */

  @scope (photo-viewer) {
    dialog {
      inline-size: 100dvw;
      block-size: 100dvh;
      max-inline-size: none;
      max-block-size: none;
      margin: 0;
      padding: 0;
      border: 0;
      background: light-dark(oklch(97% 0.004 80 / 0.97), oklch(9% 0.005 260 / 0.97));
      color: var(--text);
      overflow: hidden;
      overscroll-behavior: contain;

      &[open] {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 24rem;
      }
      &::backdrop { background: transparent; }
    }

    .stage {
      position: relative;
      display: grid;
      place-items: center;
      min-block-size: 0;
      padding: clamp(0.5rem, 2.5vw, 2rem);
      cursor: zoom-out;

      img {
        max-inline-size: 100%;
        max-block-size: calc(100dvh - 2 * clamp(0.5rem, 2.5vw, 2rem));
        inline-size: auto;
        block-size: auto;
        object-fit: contain;
        border-radius: var(--radius-s);
        box-shadow: 0 30px 80px -30px oklch(0% 0 0 / 0.6);
        cursor: zoom-in;
        user-select: none;
        view-transition-name: photo;
      }
    }

    /* Zoomed: actual pixels, scroll to pan. */
    dialog.zoomed .stage {
      place-items: start;
      overflow: auto;
      img { max-inline-size: none; max-block-size: none; border-radius: 0; cursor: zoom-out; margin: auto; }
    }

    .nav {
      position: absolute;
      inset-block-start: 50%;
      translate: 0 -50%;
      display: grid;
      place-items: center;
      inline-size: 3rem;
      block-size: 3rem;
      border: 1px solid var(--line);
      border-radius: 50%;
      background: color-mix(in oklch, var(--surface) 70%, transparent);
      backdrop-filter: blur(12px);
      opacity: 0.75;
      transition: opacity 0.15s, scale 0.15s, background-color 0.15s;

      &:hover { opacity: 1; scale: 1.06; background: var(--surface); }
      &:disabled { opacity: 0; pointer-events: none; }
      &.prev { inset-inline-start: 1rem; }
      &.next { inset-inline-end: 1rem; }
    }

    .info {
      display: flex;
      flex-direction: column;
      min-block-size: 0;
      overflow: auto;
      overscroll-behavior: contain;
      border-inline-start: 1px solid var(--line);
      background: var(--bg);
      scrollbar-width: thin;
      &:focus { outline: none; }
    }

    .info-bar {
      position: sticky;
      inset-block-start: 0;
      z-index: 1;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0.6rem 0.75rem 0.6rem 1.5rem;
      background: color-mix(in oklch, var(--bg) 85%, transparent);
      backdrop-filter: blur(12px);
    }
    .position { font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); }

    .details {
      display: grid;
      gap: 1.5rem;
      padding: 0.25rem 1.5rem 2rem;
      animation: fade-in 0.2s ease;
    }

    header {
      display: grid;
      gap: 0.6rem;
      h2 { font-size: 1.375rem; letter-spacing: -0.015em; overflow-wrap: anywhere; }
    }

    .caption {
      display: flex;
      align-items: baseline;
      gap: 0.5rem;
      color: var(--muted);
      font-size: 0.9375rem;
      &::first-letter { text-transform: uppercase; }
    }
    .ai {
      flex: none;
      padding: 0 0.3rem;
      border-radius: 0.25rem;
      background: var(--accent-soft);
      color: var(--accent-strong);
      font-size: 0.625rem;
      font-weight: 750;
      letter-spacing: 0.06em;
      translate: 0 -0.1rem;
    }

    .facts {
      display: grid;
      gap: 0.9rem;
      > div { display: grid; grid-template-columns: 6.5rem 1fr; gap: 0.75rem; }
      dt { color: var(--muted); font-size: 0.8125rem; padding-block-start: 0.1rem; }
      dd { display: grid; justify-items: start; gap: 0.1rem; font-size: 0.9375rem; overflow-wrap: anywhere; }
      small { color: var(--muted); font-size: 0.8125rem; }
      a { display: inline-flex; align-items: center; gap: 0.3rem; }
      .icon { inline-size: 1rem; block-size: 1rem; }
    }

    .mono { font-family: var(--font-mono); font-size: 0.8125rem; }
    .muted { color: var(--muted); }

    .filter-link {
      padding: 0;
      border: 0;
      background: none;
      text-align: start;
      text-decoration: underline dotted var(--line-strong);
      text-underline-offset: 0.25em;
      &:hover { color: var(--accent-strong); text-decoration: underline solid currentColor; }
    }

    .pill {
      display: inline-block;
      margin-block-start: 0.2rem;
      padding: 0.05rem 0.5rem;
      border-radius: 99px;
      font-size: 0.6875rem;
      font-weight: 700;
      letter-spacing: 0.03em;
      text-transform: uppercase;
      &.ok { color: var(--ok); background: color-mix(in oklch, var(--ok) 14%, transparent); }
      &.warn { color: var(--warn); background: color-mix(in oklch, var(--warn) 14%, transparent); }
    }

    section {
      display: grid;
      gap: 0.6rem;
      h3 {
        font-size: 0.75rem;
        font-weight: 650;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--muted);
      }
    }

    .scores {
      ul { display: grid; gap: 0.4rem; }
      li {
        display: grid;
        grid-template-columns: 6.5rem 1fr 2.75rem;
        align-items: center;
        gap: 0.75rem;
        font-size: 0.875rem;
        color: var(--muted);
        &[data-chosen] { color: var(--text); font-weight: 600; }
        .mono { text-align: end; }
      }
      .bar {
        block-size: 6px;
        border-radius: 99px;
        background: linear-gradient(to right, var(--bar-color, var(--line-strong)) calc(var(--score) * 100%), var(--surface-2) 0);
      }
      [data-chosen] .bar { --bar-color: var(--accent); }
    }

    .tags {
      display: flex;
      flex-wrap: wrap;
      gap: 0.35rem;
      .filter-link {
        padding: 0.15rem 0.55rem;
        border-radius: 99px;
        background: var(--surface-2);
        font-size: 0.8125rem;
        text-decoration: none;
        &:hover { background: var(--accent-soft); }
      }
    }

    .description { white-space: pre-line; font-size: 0.875rem; color: var(--muted); }

    .attribution {
      padding: 0.85rem 1rem;
      border-radius: var(--radius);
      background: var(--surface-2);
      grid-template-columns: 1fr auto;
      align-items: start;
      h3 { grid-column: 1 / -1; }
      p { font-size: 0.8125rem; overflow-wrap: anywhere; }
      .small-button { .icon { inline-size: 1rem; block-size: 1rem; } }
      .copied { color: var(--ok); border-color: currentColor; }
    }

    .actions { display: flex; flex-wrap: wrap; gap: 0.5rem; .icon { inline-size: 1rem; block-size: 1rem; } }

    /* Narrow: photo on top, details scroll underneath. (The dialog is the
       viewport's width, so a media query is the container query here.) */
    @media (width < 52rem) {
      dialog[open] {
        grid-template-columns: 1fr;
        grid-template-rows: auto;
        overflow: auto;
      }
      .stage {
        block-size: 68dvh;
        img { max-block-size: calc(68dvh - 1rem); }
      }
      .info { overflow: visible; border-inline-start: 0; border-block-start: 1px solid var(--line); }
      /* Keep close and position reachable over the photo while the details scroll. */
      .info-bar {
        position: fixed;
        inset: 0 0 auto;
        padding-block-start: max(0.6rem, env(safe-area-inset-top));
        background: linear-gradient(oklch(0% 0 0 / 0.45), transparent);
        backdrop-filter: none;
        color: white;
        .position, .icon-button { color: inherit; }
      }
      .nav { inline-size: 2.5rem; block-size: 2.5rem; &.prev { inset-inline-start: 0.5rem; } &.next { inset-inline-end: 0.5rem; } }
    }
  }

  @keyframes fade-in { from { opacity: 0; } }
}

/* ---------------------------------------------------------- transitions -- */

@layer components {
  ::view-transition-group(photo) {
    animation-duration: 0.38s;
    animation-timing-function: var(--ease-out);
  }
  ::view-transition-old(photo), ::view-transition-new(photo) {
    /* Thumbnail is cropped, the viewer isn't: fill the box instead of squashing. */
    object-fit: cover;
    block-size: 100%;
    overflow: clip;
  }
  ::view-transition-group(results) { animation-duration: 0.2s; }
  ::view-transition-old(results) { animation: 0.15s ease both fade-out; }
  ::view-transition-new(results) { animation: 0.25s ease both fade-in; }
  @keyframes fade-out { to { opacity: 0; } }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after, ::view-transition-group(*) {
      animation-duration: 0.01ms !important;
      transition-duration: 0.01ms !important;
    }
  }
}

/* ------------------------------------------------------------ utilities -- */

@layer utilities {
  .visually-hidden {
    position: absolute !important;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  [hidden] { display: none !important; }
}
