/* LINES is independent of FIELDS and the private Studio. */
.lines-head { display:flex; justify-content:space-between; align-items:center; gap:24px; padding:28px var(--pad); font-size:12px; letter-spacing:.13em; }
.lines-head a { padding:8px 0; }
a:focus-visible, button:focus-visible, summary:focus-visible { outline:2px solid var(--paper); outline-offset:5px; }
.lines-index { padding:32px var(--pad) 64px; }
.city { display:block; max-width:900px; margin:auto; }
.city img { display:block; width:100%; height:68vh; object-fit:contain; }
.city-label { display:flex; align-items:baseline; gap:24px; border-top:1px solid var(--rule); padding-top:20px; margin-top:24px; }
.city-name { flex:1; font:clamp(40px,6vw,76px)/1 var(--serif); letter-spacing:-.04em; }
.madrid { display:grid; grid-template-columns:minmax(220px,1fr) minmax(0,2.4fr); gap:clamp(28px,5vw,80px); padding:20px var(--pad) 64px; align-items:start; }
.madrid-margin { position:sticky; top:32px; padding-top:32px; }
.eyebrow { font-size:12px; letter-spacing:.16em; text-transform:uppercase; color:#a4a399; }
.madrid h1 { font:clamp(48px,6vw,88px)/1 var(--serif); font-weight:400; letter-spacing:-.045em; margin:20px 0 64px; }
.mode-buttons { display:flex; gap:10px; margin:14px 0; }
.mode-buttons button { width:50px; height:48px; padding:0; border:1px solid #77786e; background:transparent; color:var(--paper); font:20px var(--serif); cursor:pointer; transition:background .2s,color .2s; }
.mode-buttons button[aria-pressed="true"] { color:var(--night); background:var(--paper); border-color:var(--paper); }
.mode-buttons button:disabled { opacity:.3; cursor:default; }
.photo-col { display:flex; flex-direction:column; min-width:0; }
.invert-caption {
  margin:0 0 14px;
  font:italic 500 clamp(15px,1.6vw,19px)/1.35 var(--serif);
  color:var(--paper);
  text-align:center;
  text-transform:lowercase;
  letter-spacing:.01em;
  opacity:0;
  visibility:hidden;
  transform:translateY(-4px);
  transition:opacity .5s var(--ease), transform .5s var(--ease), visibility 0s linear .5s;
}
body.is-inverting .invert-caption {
  opacity:1;
  visibility:visible;
  transform:translateY(0);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
.madrid-photo { width:100%; min-width:0; margin:0; }
.photo-pair { display:grid; }
.photo-pair img { grid-area:1/1; display:block; width:100%; height:auto; }
/* The invert is a live CSS filter on the same photograph, not a swap to a
   second pre-edited file — and the two sets don't share one look. Set I
   tips cool/silver, set II tips warm/amber, so pressing I vs II reads as
   two different ways through the same moment rather than one generic
   photo-negative applied twice. The slow transition (rather than a hard
   cut) is deliberate: it should feel like tipping from one path into the
   other, not like a filter switching on. */
.photo-normal { transition:filter .9s var(--ease); }
[data-invert="i"].is-inverted .photo-normal,
.photo-viewer img.is-inverted[data-invert="i"] {
  filter:invert(1) hue-rotate(195deg) saturate(.85) brightness(1.04) contrast(1.02);
}
[data-invert="ii"].is-inverted .photo-normal,
.photo-viewer img.is-inverted[data-invert="ii"] {
  filter:invert(1) hue-rotate(18deg) saturate(1.2) brightness(1.02) contrast(1.05);
}
.photo-viewer img { transition:filter .9s var(--ease); }
figcaption { display:flex; justify-content:space-between; gap:20px; margin-top:14px; font-size:12px; letter-spacing:.05em; color:#a4a399; }
@media(max-width:760px) {
  .madrid { grid-template-columns:1fr; }
  .madrid-margin { position:static; padding-top:0; }
  .madrid h1 { margin-bottom:28px; }
}
@media(prefers-reduced-motion:reduce) { .photo-normal, .photo-viewer img, .mode-buttons button { transition:none; } }

/* Three columns, two rows; empty slots do not participate in inversion. */
.photo-sequence { min-width:0; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:40px 24px; align-items:start; }
.photo-pair, .photo-placeholder { aspect-ratio:3 / 2; position:relative; overflow:hidden; }
/* Safari has a known bug where an absolutely-positioned, object-fit image
   loaded off-screen (as every photo past the first row of this horizontal
   scroller is) can finish decoding without ever actually being painted —
   the pixels are there, layout is correct, but nothing draws until some
   later interaction (a click, a hover) forces a repaint. Promoting the
   image to its own compositing layer sidesteps that: it paints as soon as
   it's ready instead of waiting on an unrelated repaint to reveal it. */
.photo-pair img { position:absolute; inset:0; width:100%; height:100%; min-height:0; object-fit:cover; object-position:center; transform:translateZ(0); backface-visibility:hidden; }
.photo-placeholder { border:1px solid var(--rule); background:rgba(236,233,223,.018); }
.is-placeholder figcaption { color:var(--quiet); }
.madrid-foot { display:flex; justify-content:space-between; align-items:baseline; gap:20px; padding:0 var(--pad) 40px; text-align:left; font-size:12px; color:#a4a399; }
.rights { font-size:10px; letter-spacing:.12em; color:var(--dormant); white-space:nowrap; }
.madrid-foot-tags { font-size:10px; letter-spacing:.1em; text-transform:lowercase; color:var(--quiet); white-space:nowrap; }
@media(max-width:760px) { .madrid-foot-tags { display:none; } }
.madrid-foot a { display:inline-block; padding:12px 0; }
@media(max-width:760px) { .photo-sequence { gap:28px 14px; } }

/* User-provided section quote — wording preserved verbatim. */
.madrid h1:has(+ .madrid-quote) { margin-bottom:24px; }
.madrid-quote { max-width:24ch; margin:0 0 36px; color:#a4a399; font:italic 18px/1.5 var(--serif); }

/* Entire six-frame gallery within the viewport. */
.gallery-page .lines-head { height:56px; min-height:56px; padding:8px var(--pad); }
.gallery-page .madrid { display:grid; grid-template-columns:minmax(190px,.62fr) minmax(0,2.8fr); align-items:center; gap:clamp(32px,5vw,96px); padding:8px var(--pad) 0; min-height:calc(100svh - 106px); }
.gallery-page .madrid-margin { position:static; padding:0; width:100%; text-align:left; }
.gallery-page .madrid h1 { font:500 clamp(20px,2.3vw,30px)/1.2 var(--sans); letter-spacing:.12em; margin:0 0 10px; }
.gallery-page .madrid-quote { max-width:none; white-space:nowrap; font-size:clamp(12px,1.7vw,18px); margin:0 0 12px; }
.gallery-page .mode-buttons { justify-content:flex-start; margin:0; }
.gallery-page .mode-buttons button { height:36px; width:42px; }
/* More than six photographs now, so the grid runs in COLUMNS: the index goes
   down each column, then the columns carry on to the right. Only this element
   scrolls — the margin column is a grid sibling of it, so the title, controls
   and quote stay put. Column width is derived from the row height so each
   frame keeps its 3:2 proportion without a fixed aspect on the container. */
.gallery-page .photo-sequence {
  width:100%; margin:0; justify-self:stretch; align-self:center;
  height:auto; max-height:calc(100svh - 116px);
  aspect-ratio:auto;
  grid-auto-flow:column;
  /* Explicit tracks, not implicit ones from grid-auto-columns alone: with
     8 photographs at 2 rows that's 4 columns. Safari has a real bug where
     a grid's trailing implicit column(s) — generated purely from
     grid-auto-columns inside a scrolling (overflow-x) container — can fail
     to size or paint correctly, which is what was making the very last
     photograph (#8) vanish. Writing the columns out removes the implicit
     step entirely. If photographs are added or removed, update the 4 and
     the row count together so the two stay in sync. */
  grid-template-columns: repeat(4, calc((100% - 40px) / 3));
  grid-template-rows:repeat(2,auto);
  /* Kept only as a fallback for a photo count the explicit columns above
     don't cover. */
  grid-auto-columns:calc((100% - 40px) / 3);
  gap:16px 20px;
  overflow-x:auto; overflow-y:hidden;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scrollbar-width:none;
}
.gallery-page .photo-sequence::-webkit-scrollbar { display:none; }
.gallery-page .photo-sequence:focus-visible { outline:2px solid var(--paper); outline-offset:4px; }
.gallery-page .madrid-photo { scroll-snap-align:start; }
.gallery-page .madrid-photo { display:flex; min-height:0; flex-direction:column; }
.gallery-page .photo-pair, .gallery-page .photo-placeholder { min-height:0; flex:0 0 auto; }
.gallery-page .madrid-photo figcaption { margin-top:6px; font-size:11px; line-height:16px; }
.gallery-page .madrid-foot { height:50px; padding:0 var(--pad); display:flex; align-items:center; justify-content:space-between; }

/* light-trails and spiral-tunnel used to run as full-height accent
   columns here ("tall"); removed by request so every photo in the
   sequence — including these two — is the same size. */


/* Revealed, the dialog is only the photograph: no frame, no ground. It
   centres within the band the photo grid itself occupies (below the
   56px header) rather than the full viewport, so it lines up with the
   two rows of the main grid instead of sitting higher, over the header. */
.aside-dialog:has(.aside-reveal:not([hidden])) {
  border:0; padding:0; width:auto; height:auto; max-width:none; max-height:none;
  background:transparent;
  inset:106px 0 0 0; margin:auto;
}
.aside-reveal { margin:0; outline:0; }
.aside-reveal img {
  display:block;
  height:min(78dvh, 860px);
  /* Narrower than the frame it was shot in: the sides are cropped to a
     standing arch. The figure is near centre, so the crop stays off them. */
  aspect-ratio:52 / 100;
  width:auto;
  max-width:92vw;
  object-fit:cover;
  object-position:50% 50%;
  /* The curve takes only the top corners; the centre column is untouched. */
  border-radius:50% 50% 0 0 / 30% 30% 0 0;
}
@media (prefers-reduced-motion:no-preference) {
  .aside-reveal:not([hidden]) img { animation:aside-arrive .58s cubic-bezier(.22,.72,.16,1) both; }
  @keyframes aside-arrive {
    from { opacity:0; transform:translateY(26px) scale(.97); }
    to   { opacity:1; transform:none; }
  }
}
@media(max-width:760px) {
  .aside-dialog:has(.aside-reveal:not([hidden])) { inset:76px 0 0 0; }
  .aside-reveal img { height:min(68dvh, 620px); }
}
.photo-pair[role="button"] { cursor:zoom-in; }
.photo-pair:focus-visible { outline:2px solid var(--paper); outline-offset:4px; }
.photo-viewer { width:100vw; height:100dvh; max-width:100vw; max-height:100dvh; border:0; padding:48px 24px 24px; background:#080906; color:var(--paper); }
.photo-viewer::backdrop { background:rgba(0,0,0,.92); }
.photo-viewer[open] { display:flex; align-items:center; justify-content:center; }
.photo-viewer img { max-width:100%; max-height:100%; width:auto; height:auto; object-fit:contain; }
.viewer-close { position:absolute; top:12px; right:24px; background:none; color:inherit; border:0; padding:8px; font:14px var(--sans); cursor:pointer; }
html:has(.photo-viewer[open]) { overflow:hidden; }

@media(max-width:760px) {
  .gallery-page .madrid { display:flex; min-height:auto; align-items:stretch; }
  .gallery-page .madrid-margin { text-align:left; }
  .gallery-page .mode-buttons { justify-content:flex-start; }
  /* Narrow: back to a vertical stack, no sideways scrolling. */
  .gallery-page .photo-sequence { width:100%; height:auto; aspect-ratio:auto; grid-auto-flow:row; grid-template-columns:repeat(3,minmax(0,1fr)); grid-template-rows:none; grid-auto-columns:auto; overflow:visible; scroll-snap-type:none; }
  .gallery-page .madrid-photo { aspect-ratio:3 / 4; }
  .gallery-page .madrid-photo figcaption { flex:0 0 auto; }
}

/* Arrival from the gate: a soft edge travels left to right, uncovering the
   page as it goes. A sliding cover rather than a mask or a fade on the page
   itself, so it is one composited transform and never touches the gallery's
   viewport-height maths. */
@media (prefers-reduced-motion: no-preference) {
  .gallery-page::before {
    content: "";
    position: fixed;
    top: 0;
    bottom: 0;
    left: -40%;
    width: 140%;
    z-index: 40;
    pointer-events: none;
    background: linear-gradient(90deg, transparent 0%, var(--night) 30%, var(--night) 100%);
    animation: lines-arrive .62s cubic-bezier(.3, .7, .2, 1) both;
  }

  @keyframes lines-arrive {
    from { transform: translateX(0); }
    to   { transform: translateX(140%); }
  }
}

/* LINES title — the name carries the weight, the mark sits beside it,
   the same relationship the gate uses. */
.lines-title { margin:0 0 14px; font:400 clamp(30px,3.6vw,54px)/.95 var(--serif); letter-spacing:-.035em; color:var(--paper); }
.gallery-page .madrid h1.lines-title { font:400 clamp(30px,3.6vw,54px)/.95 var(--serif); letter-spacing:-.035em; margin:0 0 12px; }
.title-mark { margin-left:.5em; font:600 10px/1 var(--sans); letter-spacing:.16em; text-transform:uppercase; color:var(--quiet); white-space:nowrap; }

/* Quotes sit below the controls, given air. The line is a control in its own
   right: pressing it opens a short note beneath. */
.quotes { margin-top:clamp(26px,5vh,64px); max-width:none; }
.gallery-page .quotes { margin-top:clamp(22px,4vh,48px); }
.quote { margin:0; }
.quote blockquote { margin:0; }
/* Small enough to hold one line: the quote is an aside, not a headline. */
.quote-open {
  display:block; width:100%; padding:0 0 3px; border:0; background:transparent;
  font:italic 10px/1.4 var(--serif);
  color:#a4a399; text-align:left; cursor:pointer;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  border-bottom:1px solid var(--rule);
  transition:color .25s ease, border-color .25s ease;
}
.quote-open::before {
  content:"\203A  ";
  font-family:var(--sans);
  font-style:normal;
  color:var(--dormant);
  transition:color .25s ease;
}
.quote-open:hover { color:var(--paper); border-bottom-color:var(--quiet); }
.quote-open:hover::before,
.quote-open[aria-expanded="true"]::before { color:var(--quiet); }
.quote-open[aria-expanded="true"] { color:var(--paper); border-bottom-color:var(--quiet); }
.quote-open:focus-visible { outline:2px solid var(--paper); outline-offset:4px; }
.quote-note {
  margin:14px 0 0; font:13px/1.6 var(--sans); letter-spacing:.01em; color:var(--quiet);
  border-left:1px solid var(--rule); padding-left:14px;
}
@media (prefers-reduced-motion:no-preference) {
  .quote-note:not([hidden]) { animation:quote-note-in .34s cubic-bezier(.22,.72,.16,1) both; }
  @keyframes quote-note-in { from { opacity:0; transform:translateY(-4px) } to { opacity:1; transform:none } }
}

/* The ? sits beside the inversion controls without joining that group. */
.control-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:14px 0; }
.gallery-page .control-row { margin:0; }
.control-row .mode-buttons { margin:0; }
.aside-open { width:50px; height:48px; padding:0; border:1px solid #77786e; background:transparent; color:var(--paper); font:20px var(--serif); cursor:pointer; transition:background .2s,color .2s; }
.aside-open:hover { color:var(--night); background:var(--paper); border-color:var(--paper); }
.gallery-page .aside-open { height:36px; width:42px; font-size:16px; }

/* The aside itself. */
.aside-dialog { max-width:min(92vw,760px); border:1px solid var(--rule); padding:0; background:#080906; color:var(--paper); }
.aside-dialog::backdrop { background:rgba(8,9,6,.82); }
/* [hidden] is a UA rule, so any display declaration outranks it. .aside-form
   is display:flex, which is why hiding it did nothing. Settle it globally. */
[hidden] { display:none !important; }
.aside-form { display:flex; flex-direction:column; gap:12px; padding:30px; }
.aside-text { margin:0; font:italic clamp(17px,2vw,23px)/1.45 var(--serif); color:var(--paper); }
.aside-label { font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--quiet); }
.aside-code { width:9ch; padding:10px 12px; border:1px solid var(--rule); background:transparent; color:var(--paper); font:16px/1 var(--sans); letter-spacing:.3em; }
.aside-code:focus-visible { outline:2px solid var(--paper); outline-offset:3px; }
.aside-miss { min-height:1.2em; margin:0; font-size:12px; letter-spacing:.04em; color:#a4a399; }
.aside-actions { display:flex; gap:10px; margin-top:4px; }
.aside-enter, .aside-close { min-height:44px; padding:0 18px; border:1px solid #77786e; background:transparent; color:var(--paper); font:12px var(--sans); letter-spacing:.1em; cursor:pointer; transition:background .2s,color .2s; }
.aside-enter:hover, .aside-close:hover { color:var(--night); background:var(--paper); border-color:var(--paper); }
@media (prefers-reduced-motion:reduce) { .aside-open, .aside-enter, .aside-close { transition:none; } }

/* Hidden easter egg: click L, then N, then E in the LINES title (in that
   order) to open a 2x4 strip of two photographs, repeated and alternating.
   No visual affordance on the letters themselves -- it's meant to be found,
   not advertised. */
[data-lines-secret-letter] { cursor:default; display:inline-block; transition:transform .12s ease, opacity .12s ease; }
[data-lines-secret-letter].is-secret-pressed { transform:scale(.86); opacity:.55; }

/* On completing L-N-E, the three letters slide together (see lines.js)
   while the other two (I, S) fade out of the way. */
[data-lines-secret-letter].is-secret-converging {
  transition:transform .56s cubic-bezier(.65,0,.35,1);
  position:relative; z-index:2;
}
[data-lines-secret-letter].is-secret-fading {
  transition:opacity .3s ease;
  opacity:0;
}
@media (prefers-reduced-motion:reduce) {
  [data-lines-secret-letter] { transition:none; }
  [data-lines-secret-letter].is-secret-converging,
  [data-lines-secret-letter].is-secret-fading { transition:none; }
}

/* Small transient popup that surfaces beneath the title on every letter
   click, hinting at progress through the secret sequence above without
   giving away what the sequence actually is. */
.lines-secret-hint {
  margin:-2px 0 14px; min-height:1.1em;
  font:500 12px/1.2 var(--sans); letter-spacing:.03em; text-transform:uppercase;
  color:var(--paper); opacity:0;
  transition:opacity .25s ease;
  pointer-events:none;
}
.lines-secret-hint.is-visible { opacity:.62; }
@media (prefers-reduced-motion:reduce) {
  .lines-secret-hint { transition:none; }
}
.lines-secret-dialog {
  width:min(84vw, 420px); max-width:84vw; max-height:90dvh;
  border:0; padding:0; background:#080906; color:var(--paper);
  overflow-y:auto; overflow-x:hidden;
  scrollbar-width:none;
}
.lines-secret-dialog::-webkit-scrollbar { display:none; }
.lines-secret-dialog::backdrop { background:rgba(8,9,6,.9); }
.lines-secret-dialog[open] { display:block; }
.lines-secret-dialog .viewer-close {
  position:sticky; top:0; left:100%;
  float:right;
  background:#080906; color:inherit; border:0; padding:10px 14px;
  font:14px var(--sans); cursor:pointer;
  z-index:1;
}
.lines-secret-grid {
  display:grid;
  grid-template-columns:repeat(2, 1fr);
  grid-auto-rows:auto;
  gap:2px;
  clear:both;
  padding:0 2px 2px;
}
.lines-secret-cell { aspect-ratio:4 / 3; overflow:hidden; display:flex; align-items:center; justify-content:center; background:#000; }
.lines-secret-cell img { max-width:100%; max-height:100%; width:auto; height:auto; object-fit:contain; }
@media (prefers-reduced-motion:no-preference) {
  .lines-secret-dialog[open] .lines-secret-cell {
    animation:lines-secret-cell-in .5s cubic-bezier(.22,.72,.16,1) both;
  }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(1) { animation-delay:.02s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(2) { animation-delay:.07s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(3) { animation-delay:.12s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(4) { animation-delay:.17s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(5) { animation-delay:.22s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(6) { animation-delay:.27s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(7) { animation-delay:.32s; }
  .lines-secret-dialog[open] .lines-secret-cell:nth-child(8) { animation-delay:.37s; }
  @keyframes lines-secret-cell-in {
    from { opacity:0; transform:scale(1.04); }
    to   { opacity:1; transform:none; }
  }
}
@media (prefers-reduced-motion:reduce) {
  .lines-secret-dialog[open] .lines-secret-cell { animation:none; }
}
html:has(.lines-secret-dialog[open]) { overflow:hidden; }
@media(max-width:600px) {
  .lines-secret-dialog { width:100vw; max-width:100vw; max-height:100dvh; height:100dvh; }
}
