/* =========================================================================
   Milites Maioricarum — styles.css
   Implements the STYLE & FLOW BRIEF. One grotesk, one mono, monochrome.
   Layout is built only from the five patterns (A–E). Nothing decorative.
   ========================================================================= */

/* ---- self-hosted fonts ------------------------------------------------- */
@font-face{
  font-family:'Old London';
  src:url('../fonts/OldLondon.woff2') format('woff2');
  font-weight:400;
  font-style:normal;
  font-display:swap;
}
@font-face{
  font-family:'EB Garamond';
  src:url('../fonts/EBGaramond-Regular.woff2') format('woff2');
  font-weight:400;
  font-style:normal;
  font-display:swap;
}

/* ---- reset ------------------------------------------------------------- */
*,*::before,*::after{ box-sizing:border-box; }
*{ margin:0; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; overflow-x:clip; }
body{
  background:#220e0e;
  color:var(--fg);
  font-family:var(--font-sans);
  font-weight:300;
  font-size:var(--step-0);
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,video,svg{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
ul,ol,dl{ list-style:none; padding:0; }

/* ---- shared type ------------------------------------------------------- */
.mono{
  font-family:var(--font-sans);
  font-size:var(--step--1);
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--fg-mute);
  font-weight:400;
}
h1,h2,h3{ font-weight:500; line-height:.98; }

/* ---- focus / a11y ------------------------------------------------------ */
:where(a,button,summary,input,textarea,[tabindex]):focus-visible{
  outline:1px solid var(--fg);
  outline-offset:4px;
}
.skip{
  position:fixed; top:8px; left:8px; z-index:1000;
  padding:10px 14px; background:var(--fg); color:var(--bg);
  font-family:var(--font-sans); font-size:var(--step--1);
  transform:translateY(-160%); transition:transform .2s var(--ease);
}
.skip:focus{ transform:translateY(0); }

/* ---- page background --------------------------------------------------- */
/* The six brown backgrounds (src-assets/img/backgrounds/*.png) pre-stacked, in
   filename order, into one vertical WebP tile. Applied to the wrapper that
   begins right below the hero video (and to the footer), so the texture
   starts just under the home video — never behind or above it. repeat-y
   tiles the six-image unit down the page — seamless, no black gaps —
   restarting from the first image whenever the run is longer than the six.
   Scrolls with the page (default attachment); scales to any width via
   100% auto. A flat dark overlay keeps light text legible over the
   brighter scenes. --bg is the base colour shown before the tile loads. */
.page-bg{
  background-color:var(--bg);
  background-image:
    linear-gradient(rgba(10,10,10,.5),rgba(10,10,10,.5)),
    url('../img/backgrounds/web_background_tile.webp');
  background-repeat:no-repeat,repeat-y;
  background-position:top center,top center;
  background-size:cover,100% auto;
}

/* ---- layout primitives ------------------------------------------------- */
.wrap{ max-width:var(--max); margin-inline:auto; padding-inline:var(--pad); }
.section{ padding-block:var(--section); border-top:1px solid var(--line); }
.section:first-of-type{ border-top:0; }

/* === A · Section head ==================================================== */
.head{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--gap);
  align-items:start;
}
.head__marker{
  margin-bottom:14px;
  color:var(--fg-mute);
  text-transform:uppercase;
  letter-spacing:.14em;
}
.head__body{ grid-column:1; }
.head__title{
  font-size:var(--step-3);
  letter-spacing:-.035em;
  line-height:.96;
}
.head__lead{
  margin-top:18px;
  font-size:var(--step-1);
  color:var(--fg-dim);
}
.head__title em{ font-style:italic; }

/* content sits below the head, offset to align with the head body column */
.block{
  margin-top:clamp(28px,4vw,56px);
  display:grid;
  grid-template-columns:1fr;
  gap:var(--gap);
}
.block > *{ grid-column:1; }
.block--full > *{ grid-column:1 / -1; }

/* === B · Media block ==================================================== */
.media{
  width:100%;
  aspect-ratio:var(--ar,16/7);
  border-radius:var(--radius);
  overflow:hidden;
  background:var(--bg-raised);
}
.media img,.media video{ width:100%; height:100%; object-fit:cover; filter:saturate(.8); }
.media--wide{ --ar:21/9; }

/* placeholder surface — swap for <img>/<video> when real assets arrive */
.ph{
  position:relative;
  background:
    repeating-linear-gradient(135deg,transparent 0 22px,rgba(255,255,255,.012) 22px 23px),
    var(--bg-raised);
  border:1px solid var(--line);
  display:grid; place-items:center;
  overflow:hidden;
}
.media.ph{ border-radius:var(--radius); }
.ph::after{
  content:attr(data-ph);
  font-family:var(--font-sans);
  font-size:var(--step--1);
  letter-spacing:.09em; text-transform:uppercase;
  color:var(--fg-mute);
  padding:0 12px; text-align:center;
}

/* === C · Spec rows ====================================================== */
.specs{ border-top:1px solid var(--line); }
.spec{
  display:grid;
  grid-template-columns:180px 1fr auto;
  gap:var(--gap);
  align-items:baseline;
  padding:20px 0;
  border-bottom:1px solid var(--line);
}
.spec__label{ padding-top:.35em; }
.spec__value{ font-size:var(--step-2); letter-spacing:-.02em; color:var(--fg); }
.spec__value a{ border-bottom:1px solid var(--line-strong); transition:opacity .25s var(--ease); }
.spec__value a:hover{ opacity:.6; }
.spec__meta{ text-align:right; align-self:baseline; }

/* === D · Card row ======================================================= */
.cards{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:var(--gap);
}
.card{
  background:var(--bg-raised);
  border:1px solid transparent;
  border-radius:0;
  padding:0 0 20px;
  transition:border-color .3s var(--ease);
  overflow:hidden;
}
/* hover only on cards that are actually links — a static card must not react */
a.card:hover{ border-color:var(--line-strong); }
.card__media{
  aspect-ratio:4/3;
  overflow:hidden;
  margin-bottom:18px;
}
/* Size the <img> itself, not the <picture> wrapper — a wrapper that generates
   no box can't carry the sizing, and the image would render at full size. */
.card__media picture{ display:block; }
.card__media > *,
.card__media img{ width:100%; height:100%; object-fit:cover; transition:transform var(--dur) var(--ease); filter:saturate(.8); }
/* Photo keeps its own proportions — the image sets the height, nothing is
   cropped or squashed. The width/height attrs reserve the box, so no shift. */
.card__media--free{ aspect-ratio:auto; }
.card__media--free img{ height:auto; display:block; }
a.card:hover .card__media > *,
a.card:hover .card__media.ph{ transform:scale(1.03); }
.card__title{ font-size:var(--step-1); font-weight:500; letter-spacing:-.02em; padding:0 18px; }
.card__line{ margin-top:8px; color:var(--fg-dim); padding:0 18px; }
.card__line + .card__title{ margin-top:6px; }   /* month sits above the title */
.cards--3{ grid-template-columns:repeat(3,1fr); }

/* === E · Text row list ================================================== */
.rows{ border-top:1px solid var(--line); }
.row{
  display:grid;
  grid-template-columns:160px minmax(0,1fr) minmax(0,1.2fr) auto;
  gap:var(--gap);
  align-items:center;
  padding:22px 0;
  border-bottom:1px solid var(--line);
  transition:opacity .25s var(--ease);
}
/* hover-capable only: on touch the state sticks after a tap, which would leave
   a just-expanded synopsis greyed out */
@media (hover:hover){ .row:hover{ opacity:.55; } }
/* .row--curt rows are <li> grids: the title link stretches over the whole row
   so anywhere is clickable, and the synopsis toggle overrides it on phones. */
.row--curt{ position:relative; }
.row__link::after{ content:''; position:absolute; inset:0; }
.row__toggle{ display:none; }
.row__thumb{ position:relative; width:160px; aspect-ratio:16/9; overflow:hidden; background:var(--bg-raised); }
.row__thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.row__play{ position:absolute; inset:0; margin:auto; width:28px; height:28px; fill:#fff; opacity:.85; }
.row__title{ font-size:var(--step-2); letter-spacing:-.02em; }
.row__mid{ color:var(--fg-dim); }
.row__meta{ text-align:right; }

/* === image grid (§05) =================================================== */
.grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:var(--gap);
}
.tile{
  aspect-ratio:1/1;
  overflow:hidden;
  transition:opacity .25s var(--ease);
}
.tile > *{ width:100%; height:100%; object-fit:cover; transition:transform var(--dur) var(--ease); filter:saturate(.8); }
.tile:hover > *{ transform:scale(1.03); }
/* <picture> is only a wrapper, so the fit has to land on the <img> inside it */
.tile picture{ display:block; }
.tile img{ display:block; width:100%; height:100%; object-fit:cover; }

/* --- mosaic: irregular but gapless -------------------------------------
   A fixed 6-column grid whose rows are half a column wide, so every tile is
   placed on an exact whole number of half-columns and the eight of them tile
   the 6x15 board with no holes and no leftovers. The container aspect-ratio
   (6 cols / 7.5 col-units of height) is what makes a row half a column tall;
   the row spans then encode each photo's own shape — 4x4 = 2:1 panorama,
   2x6 = 2:3 portrait, 2x3 = 4:3 — so nothing is cropped hard.
   Rows/columns are named on the tiles themselves, below. */
.mosaic{
  display:grid;
  grid-template-columns:repeat(6,1fr);
  grid-template-rows:repeat(15,1fr);
  gap:var(--gap);
  aspect-ratio:4/5;
}
.mosaic .tile{ aspect-ratio:auto; min-height:0; background:var(--bg-raised); }
.mosaic .tile:nth-child(1){ grid-column:1/5;  grid-row:1/5;  }  /* 2.23 wide */
.mosaic .tile:nth-child(2){ grid-column:5/7;  grid-row:1/7;  }  /* 0.67 tall */
.mosaic .tile:nth-child(3){ grid-column:1/5;  grid-row:5/9;  }  /* 2.07 wide */
.mosaic .tile:nth-child(4){ grid-column:5/7;  grid-row:7/13; }  /* 0.80 tall */
.mosaic .tile:nth-child(5){ grid-column:1/5;  grid-row:9/13; }  /* 1.78 wide */
.mosaic .tile:nth-child(6){ grid-column:1/3;  grid-row:13/16;}  /* 4:3 */
.mosaic .tile:nth-child(7){ grid-column:3/5;  grid-row:13/16;}  /* 4:3 */
.mosaic .tile:nth-child(8){ grid-column:5/7;  grid-row:13/16;}  /* 4:3 */
/* --- lightbox ----------------------------------------------------------
   A <dialog>, so it sits in the top layer and needs no z-index of its own.
   The image is capped in both axes and never upscaled past its own width, so
   a portrait is bounded by the height and a panorama by the width. */
.lb{
  width:100vw; max-width:100vw; height:100dvh; max-height:100dvh;
  margin:0; padding:0; border:0;
  background:rgba(10,10,10,.94);
  /* the UA hides a closed dialog with display:none, so opening it back up has
     to be tied to [open] — a bare display:grid here would leave it on screen */
  display:none;
  grid-template-rows:minmax(0,1fr) auto;   /* not 1fr: that floors at the
                                              image's own height and lets a
                                              tall photo overflow the screen */
  align-items:center; justify-items:center;
}
.lb[open]{ display:grid; }
.lb::backdrop{ background:rgba(10,10,10,.94); }
/* showModal() blocks interaction but not scrolling; hold the page still */
body:has(.lb[open]){ overflow:hidden; }
.lb[open]{ animation:lb-in .28s var(--ease); }
/* flex, not grid: an auto grid row grows to the image, and the picture's
   max-height:100% would then resolve against that row rather than the screen —
   a tall photo would size itself out of the viewport. */
.lb__stage{
  width:100%; height:100%;
  min-width:0; min-height:0;
  display:flex; align-items:center; justify-content:center;
  padding:clamp(12px,3vw,40px);
  padding-bottom:0;
}
/* display:contents so the <img> is itself the flex item. As a wrapper box it
   would be auto-height, and the img's max-height:100% would have nothing
   definite to resolve against — the cap would silently do nothing. */
.lb__stage picture{ display:contents; }
.lb__stage img{
  display:block; width:auto; height:auto;
  max-width:100%; max-height:100%;
  object-fit:contain;
  filter:none;                       /* the grid's saturate(.8) stops here */
}
.lb__cap{
  display:flex; gap:14px; align-items:baseline;
  color:var(--fg-mute);
  padding:14px clamp(12px,3vw,40px) clamp(18px,3vw,28px);
  text-align:center;
}
.lb__txt{ color:var(--fg-dim); }
.lb__arrows{
  position:fixed; left:0; right:0; top:50%; transform:translateY(-50%);
  display:flex; justify-content:space-between;
  padding:0 clamp(8px,2vw,24px);
  pointer-events:none;
}
.lb__arrows > *{ pointer-events:auto; }
.lb__close{ position:fixed; top:clamp(8px,2vw,24px); right:clamp(8px,2vw,24px); }
@keyframes lb-in{ from{ opacity:0; } to{ opacity:1; } }
@media (prefers-reduced-motion:reduce){ .lb[open]{ animation:none; } }

.gallery-follow{ margin-top:24px; }
.gallery-follow a{ border-bottom:1px solid var(--line-strong); }
.gallery-follow a:hover{ opacity:.6; }

/* === accordion (§07) ==================================================== */
/* 64px marker rail, same width as the pattern-E thumbnails, so the answer can
   start on the question's own left edge instead of half a column to its left. */
.acc{ border-top:1px solid var(--line); --q-rail:64px; }
.q{ border-bottom:1px solid var(--line); }
.q > summary{
  display:grid;
  grid-template-columns:var(--q-rail) 1fr auto;
  gap:var(--gap);
  align-items:center;
  padding:22px 0;
  list-style:none;
  font-size:var(--step-2);
  letter-spacing:-.02em;
}
.q > summary::-webkit-details-marker{ display:none; }
.q__id{ align-self:center; }
.q__plus{ font-family:var(--font-sans); font-size:var(--step-1); color:var(--fg-mute); transition:transform .3s var(--ease); }
.q[open] .q__plus{ transform:rotate(45deg); }
/* Answers run at lead size (--step-1) so a 70ch measure — the widest the brief
   allows — fills most of the column instead of stranding a narrow block. */
.q__a{
  padding:0 0 28px;
  margin-left:calc(var(--q-rail) + var(--gap));
  max-width:70ch;
  color:var(--fg-dim);
  font-size:var(--step-1);
}
.q__a a{ border-bottom:1px solid var(--line-strong); }
.q__a p + p{ margin-top:.7em; }
.q__a strong{ font-weight:400; color:var(--fg); }

/* === navigation ========================================================= */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  padding:34px var(--pad) 2px;
  mix-blend-mode:difference;
  color:#fff;
}
.nav__mark{ display:inline-flex; align-items:center; gap:.55em; font-family:var(--font-sans); font-size:var(--step--1); letter-spacing:.09em; text-transform:uppercase; }
.nav__logo{ height:1.9em; width:auto; flex:none; }
.nav__links{ display:flex; gap:22px; }
.nav__links a{
  font-family:var(--font-sans); font-size:var(--step--1);
  letter-spacing:.09em; text-transform:uppercase;
  opacity:.6; transition:opacity .2s var(--ease);
}
.nav__links a:hover{ opacity:1; }

/* Language switcher. Three crawlable links, never a dropdown: search engines
   have to see /es/ and /en/ as plain <a href>. Stays visible on phones, where
   .nav__links is hidden, so it sits alone at the right of the mark. */
.nav__lang{ display:flex; align-items:center; gap:.45em; flex:none; margin-left:22px; }
.nav__lang a{
  font-family:var(--font-sans); font-size:var(--step--1);
  letter-spacing:.09em; text-transform:uppercase;
  opacity:.45; transition:opacity .2s var(--ease);
}
.nav__lang a:hover{ opacity:.85; }
.nav__lang a[aria-current]{ opacity:1; }
.nav__lang span{ opacity:.28; }

/* === hero =============================================================== */
.hero{
  position:relative;
  margin-top:88px;                    /* clear gap below the fixed nav — no overlap */
  aspect-ratio:8/3;                   /* ultra-wide band (2.66:1), wider than 21:9 */
  max-height:calc(100svh - 88px);     /* never taller than the viewport */
  min-height:420px;                   /* floor for narrow screens */
  overflow:hidden;
}
.hero__media{ position:absolute; inset:0; }
.hero__media .ph{ width:100%; height:100%; border:0; border-radius:0; }
.hero__media img,.hero__media video{ width:100%; height:100%; object-fit:cover; filter:saturate(.8); }
.hero__media video{ opacity:.9; }     /* subtle blend into the dark ground */
/* two-layer legibility scrim — dark from bottom-left, fading out; no rectangle.
   warm near-black (#0C0A08) rather than pure black against the warm imagery.  */
.hero__scrim{
  position:absolute; inset:0;
  background:
    linear-gradient(to right,
      rgba(12,10,8,.72) 0%,
      rgba(12,10,8,.45) 35%,
      rgba(12,10,8,0)   70%),
    linear-gradient(to top,
      rgba(12,10,8,.55) 0%,
      rgba(12,10,8,0)   45%);
  pointer-events:none;
}
.hero__inner{
  position:relative;
  height:100%;
  padding:clamp(22px,4vh,40px) var(--pad) clamp(24px,4vh,44px);
  display:grid;
  grid-template-rows:auto 1fr auto;
}
.hero__note{ color:rgba(244,243,240,.72); }
.hero__lede{ align-self:end; }
.hero__statement{
  font-family:var(--font-display);
  font-weight:400;
  font-size:var(--step-4);
  letter-spacing:-.02em;
  line-height:.92;
  max-width:15ch;
}
/* tagline — serif, not blackletter; left edge aligned to the eyebrow + title,
   generous air below the dense title, held to ~2 lines on desktop.            */
.hero__tagline{
  font-family:var(--font-serif);
  font-weight:400;
  font-size:clamp(1.3rem,2.4vw,1.95rem);
  line-height:1.45;
  letter-spacing:.01em;
  color:#F2EDE4;                 /* warm parchment white — not pure white */
  max-width:36ch;                /* ~2 lines on desktop: "…carrers," / "castells…" */
  margin-top:1.75rem;
  text-shadow:0 1px 14px rgba(0,0,0,.55);
}
/* short gold hairline ties the tagline to the title without drawing a box */
.hero__tagline::before{
  content:"";
  display:block;
  width:48px;
  height:1px;
  background:rgba(212,168,90,.6);
  margin-bottom:1.25rem;
}
.hero__foot{ display:flex; align-items:end; justify-content:space-between; gap:var(--gap); margin-top:26px; }
.hero__meta{ display:flex; flex-direction:column; gap:6px; text-align:right; color:#f4f3f0; background:rgba(0,0,0,.6); padding:12px 16px; border-radius:2px; }
.hero__cue{ display:inline-flex; align-items:center; gap:8px; color:rgba(244,243,240,.72); }
.hero__cue span{ display:inline-block; animation:cue 1.8s var(--ease) infinite; }
@keyframes cue{ 0%,100%{ transform:translateY(0);} 50%{ transform:translateY(4px);} }

/* === footer ============================================================= */
.foot{ border-top:1px solid var(--line); padding:var(--section) 0 40px; }
.foot__mark{
  font-family:var(--font-display);
  font-size:var(--step-5);
  font-weight:400;
  letter-spacing:-.02em;
  line-height:.9;
}

/* === parchment wordmark (both "Milites Maioricarum" titles) =============
   · the letters are filled with the parchment texture (background-clip:text)
   · a stack of blurred drop-shadows haloes the glyph shapes in every
     direction — dense at the edge, fading softly outward (no rectangle).     */
.hero__statement,
.foot__mark{
  width:fit-content;
  /* room so background-clip:text doesn't crop the blackletter descenders */
  padding:.05em .06em .18em;
  background-image:url('../img/medieval_parchment.png');
  background-repeat:no-repeat;
  background-position:center;
  background-size:cover;
  -webkit-background-clip:text;
          background-clip:text;
  -webkit-text-fill-color:transparent;
  color:transparent;
  filter:
    drop-shadow(0 0 8px rgba(0,0,0,.6))
    drop-shadow(0 0 20px rgba(0,0,0,.6))
    drop-shadow(0 0 40px rgba(0,0,0,.6));
}
.foot__cols{
  margin-top:clamp(40px,7vw,90px);
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:var(--gap);
}
.foot__col h4{ color:var(--fg-mute); font-weight:400; margin-bottom:14px; }
.foot__col a,.foot__col p{
  display:block;
  font-family:var(--font-sans); font-size:var(--step--1);
  letter-spacing:.06em; text-transform:none;
  color:var(--fg-dim);
  padding:5px 0;
}
.foot__col a{ transition:opacity .2s var(--ease); }
.foot__col a:hover{ opacity:.6; }
.foot__rule{ border:0; border-top:1px solid var(--line); margin:40px 0 18px; }
.foot__bottom{ display:flex; justify-content:space-between; gap:var(--gap); flex-wrap:wrap; text-transform:none; letter-spacing:.04em; }
.foot__legal{ margin-top:14px; color:var(--fg-mute); letter-spacing:.04em; max-width:56ch; }

/* === floating dock ====================================================== */
.dock{
  position:fixed; right:clamp(16px,3vw,32px); bottom:clamp(16px,3vw,32px); z-index:120;
  display:inline-flex; align-items:center; gap:14px;
  padding:8px 8px 8px 20px;
  background:var(--fg); color:var(--bg);
  border-radius:100px;
  box-shadow:0 12px 40px rgba(0,0,0,.45);
  opacity:0; transform:translateY(14px); pointer-events:none;
  transition:opacity .4s var(--ease), transform .4s var(--ease);
}
.dock.is-visible{ opacity:1; transform:translateY(0); pointer-events:auto; }
.dock__label{ font-family:var(--font-sans); font-size:var(--step--1); letter-spacing:.06em; text-transform:uppercase; color:#3a3a35; }
.dock__cta{
  font-family:var(--font-sans); font-size:var(--step--1);
  letter-spacing:.06em; text-transform:uppercase;
  background:var(--bg); color:var(--fg);
  padding:10px 18px; border-radius:100px;
}

/* === §01 Qui som / §02 Què fem — image carousels =======================
   Big, image-led block held inside the page gutters (a contained media block,
   so --radius applies like every other media). Slides are stacked and crossfade
   on OPACITY only (the one motion the brief allows); a single caption +
   segmented ticks + arrows ride a bottom scrim.                               */
.quefem__carousel,
.quisom__carousel{
  position:relative;
  width:100%;
  margin-top:clamp(28px,4vw,56px);
  height:clamp(440px,70svh,720px);
  overflow:hidden;
  border-radius:var(--radius);
  background:var(--bg-raised);
  touch-action:pan-y;                 /* page still scrolls; JS reads x-swipes */
}
.carousel__viewport{ position:absolute; inset:0; }
.carousel__slide{
  position:absolute; inset:0;
  opacity:0; pointer-events:none;
  transition:opacity var(--dur) var(--ease);
}
.carousel__slide.is-active{ opacity:1; pointer-events:auto; }
.carousel__slide picture{ display:block; width:100%; height:100%; }
.carousel__slide img{ width:100%; height:100%; object-fit:cover; filter:saturate(.8); }
/* video slides (§02): JS drops the clip on top of its own poster, so the frame
   is already filled when playback starts — same box, no shift either way. */
.carousel__slide video{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover; filter:saturate(.8);
}
.carousel__slide .ph{ width:100%; height:100%; border:0; border-radius:0; }

/* lateral variant (§01): slides sit in a row and the viewport translates.
   JS clones the first/last slide onto either end so the loop never rewinds. */
.carousel--slide .carousel__viewport{
  display:flex;
  transition:transform var(--dur) var(--ease);
  will-change:transform;
}
.carousel--slide .carousel__slide{
  position:relative; inset:auto;
  flex:0 0 100%;
  opacity:1; pointer-events:auto;
  transition:none;
}

/* per-slide note (§01) — one short line per photo, parked in a different
   corner each time. Serif like the hero tagline, on a plate dark enough to
   hold over any part of an image. Bottom-anchored notes clear the controls. */
.slide-note{
  position:absolute;
  z-index:1;
  margin:0;
  /* wide enough for the longest authored line, so the <br> in the markup is
     the only break — never three lines */
  max-width:min(20ch,90%);
  padding:.24em .42em;
  background:rgba(12,10,8,.62);
  font-family:var(--font-serif);
  font-weight:400;
  font-size:clamp(2rem,4.6vw,4rem);
  line-height:1.04;
  letter-spacing:-.01em;
  color:#F2EDE4;
  --note-edge:clamp(18px,2.6vw,34px);
  --note-floor:clamp(96px,9vw,128px);   /* above the ticks + arrows row */
}
.slide-note--t,
.slide-note--tl,
.slide-note--tr{ top:var(--note-edge); }
.slide-note--b,
.slide-note--bl,
.slide-note--br{ bottom:var(--note-floor); }
.slide-note--tl,
.slide-note--bl{ left:var(--note-edge); }
.slide-note--tr,
.slide-note--br{ right:var(--note-edge); text-align:right; }
.slide-note--t,
.slide-note--b{ left:50%; transform:translateX(-50%); text-align:center; }

/* §06 Curtmetratges — the player is the slide, so the arrows ride outside the
   frame: on top of it they would fight the YouTube chrome once a video runs.
   Three columns (arrow · frame · arrow) with the ticks under the frame. */
.curts{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-rows:auto auto;
  align-items:center;
  gap:var(--gap);
}
.curts__frame{ --ar:16/9; grid-column:2; grid-row:1; position:relative; }
.curts__arrow--prev{ grid-column:1; grid-row:1; }
.curts__arrow--next{ grid-column:3; grid-row:1; }
.curts__ticks{ grid-column:2; grid-row:2; justify-content:center; }
.slide-embed{ position:absolute; inset:0; width:100%; height:100%; border:0; }

/* bottom scrim + text/controls — the only darkening, and only under text */
.carousel__overlay{
  position:absolute; left:0; right:0; bottom:0;
  padding:clamp(22px,4vw,44px) clamp(20px,3vw,40px) clamp(18px,2.4vw,32px);
  display:flex; flex-direction:column; gap:clamp(16px,2.4vw,24px);
  pointer-events:none;                /* swipes pass through; controls opt back in */
  background:linear-gradient(to top,
    rgba(12,10,8,.86) 0%,
    rgba(12,10,8,.46) 46%,
    rgba(12,10,8,0)   100%);
}
.carousel__caption{ max-width:42ch; }
.carousel__caption > *{ pointer-events:auto; }
.carousel__index{ color:rgba(244,243,240,.72); margin-bottom:12px; }
.carousel__index:last-child{ margin-bottom:0; }   /* caption with no title/line */
.carousel__title{
  font-size:var(--step-3);
  letter-spacing:-.035em;
  line-height:.98;
  color:#F4F3F0;
}
.carousel__line{
  margin-top:12px;
  font-size:var(--step-1);
  color:rgba(244,243,240,.84);
  max-width:44ch;
}
.carousel__controls{
  display:flex; align-items:center; justify-content:space-between; gap:var(--gap);
  pointer-events:none;
}
.carousel__controls > *{ pointer-events:auto; }
.carousel__ticks{ display:flex; align-items:center; gap:10px; }
.carousel__tick{ padding:10px 0; display:block; }
.carousel__tick span{
  display:block; width:34px; height:3px;
  max-width:100%;
  background:rgba(255,255,255,.30);
  transition:background .3s var(--ease);
}
.carousel__tick:hover span{ background:rgba(255,255,255,.62); }
.carousel__tick.is-active span{ background:var(--fg); }
/* many slides (§01): ticks share the row instead of overflowing it on phones */
.carousel__ticks--dense{ flex:1 1 auto; min-width:0; gap:6px; margin-right:var(--gap); }
.carousel__ticks--dense .carousel__tick{ flex:1 1 0; min-width:0; }
.carousel__ticks--dense .carousel__tick span{ width:100%; }
.carousel__arrows{ display:flex; gap:10px; }
.carousel__arrow{
  width:52px; height:52px;
  display:grid; place-items:center;
  border:1px solid var(--line-strong);
  background:rgba(10,10,10,.45);
  color:#F4F3F0;
  font-size:24px; line-height:1;
  transition:background .25s var(--ease), border-color .25s var(--ease);
}
.carousel__arrow:hover{ background:rgba(10,10,10,.78); border-color:var(--fg); }

/* === motion (§5) ======================================================== */
.reveal{ opacity:0; transform:translateY(16px); transition:opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
.reveal.is-in{ opacity:1; transform:none; }

/* === responsive (§6) ==================================================== */
@media (max-width:1100px){
  .cards{ grid-template-columns:repeat(2,1fr); }
  /* Below ~1120px the 8/3 ratio + 420px floor would force the hero's WIDTH to
     420×8/3 = 1120px, pushing the whole page sideways. Drop the aspect-ratio
     here and drive height directly so width always stays 100%. The video keeps
     filling via object-fit:cover, cropped to its centre. */
  .hero{
    aspect-ratio:auto;
    height:clamp(440px, 64svh, 600px);
    min-height:0;
    max-height:none;
  }
}
@media (max-width:760px){
  .nav__links{ display:none; }
  /* Phone: the wordmark and the three codes are the only things left on the
     row, and at 360px they only just fit — drop the separators and tighten. */
  .nav__lang{ margin-left:12px; gap:.5em; }
  .nav__lang span{ display:none; }
  .head,.block{ grid-template-columns:1fr; }
  .head__body,.block > *{ grid-column:1; }
  .spec{ grid-template-columns:1fr; gap:6px; padding:18px 0; }
  .spec__meta{ text-align:left; }
  .cards{ grid-template-columns:1fr; }
  .grid{ grid-template-columns:repeat(2,1fr); }
  /* Same idea on a phone, re-cut for a 4-column board (6x27 half-column rows):
     panoramas go full width, the two portraits pair up, and nothing ends up
     narrower than half the screen. */
  .mosaic{ grid-template-columns:repeat(4,1fr); grid-template-rows:repeat(27,1fr); aspect-ratio:8/27; }
  .mosaic .tile:nth-child(1){ grid-column:1/5; grid-row:1/5;   }
  .mosaic .tile:nth-child(2){ grid-column:1/3; grid-row:5/11;  }
  .mosaic .tile:nth-child(3){ grid-column:1/5; grid-row:11/15; }
  .mosaic .tile:nth-child(4){ grid-column:3/5; grid-row:5/11;  }
  .mosaic .tile:nth-child(5){ grid-column:1/5; grid-row:15/19; }
  .mosaic .tile:nth-child(6){ grid-column:1/3; grid-row:19/22; }
  .mosaic .tile:nth-child(7){ grid-column:3/5; grid-row:19/22; }
  .mosaic .tile:nth-child(8){ grid-column:1/5; grid-row:22/28; }
  .row{ grid-template-columns:112px 1fr auto; }
  .row__mid{ display:none; }
  /* no room to indent a whole text column on a phone */
  .acc{ --q-rail:auto; }
  .q__a{ margin-left:0; }
  .row__thumb{ width:112px; aspect-ratio:16/9; }
  .row__play{ width:22px; height:22px; }
  /* No room for a synopsis column on a phone, so it folds under the row and
     opens on demand; placement is explicit because the toggle adds a cell. */
  .row--curt{ row-gap:10px; }
  .row--curt .row__thumb{ grid-column:1; grid-row:1; }
  .row--curt .row__link{ grid-column:2; grid-row:1; }
  .row--curt .row__meta{ grid-column:3; grid-row:1; }
  .row--curt .row__toggle{
    display:flex; align-items:center; gap:8px;
    grid-column:1/-1; grid-row:2;
    position:relative;            /* clears the stretched link */
    justify-self:start;
    padding:4px 0;
    font-size:var(--step--1);
    letter-spacing:.09em; text-transform:uppercase;
    color:var(--fg-mute);
  }
  .row--curt .row__plus{ font-family:var(--font-sans); transition:transform .3s var(--ease); }
  .row--curt.is-open .row__plus{ transform:rotate(45deg); }
  .row--curt .row__mid{ grid-column:1/-1; grid-row:3; }
  .row--curt.is-open .row__mid{ display:block; }
  /* Phone hero — a banner covering roughly the top half of the screen, with the
     wordmark + tagline overlaid on the clip (cropped to centre via cover). The
     repeated meta box and scroll cue only clutter a short hero on a phone, so
     they're dropped here; the "Qui som" section peeks below as the scroll cue. */
  .hero{
    margin-top:64px;
    height:56svh;
    min-height:360px;
    max-height:560px;
  }
  .hero__foot{ display:none; }
  .hero__lede{ align-self:end; }
  /* text spans the narrow frame — swap the left-to-right scrim for a vertical
     one, dark at the bottom where the title + tagline sit */
  .hero__scrim{
    background:linear-gradient(to top,
      rgba(12,10,8,.74) 0%,
      rgba(12,10,8,.42) 48%,
      rgba(12,10,8,.10) 100%);
  }
  .hero__tagline{ font-size:1.05rem; max-width:24ch; }
  /* label is hidden on mobile, so drop the extra left padding it needed —
     otherwise the CONTACTE pill sits off-centre inside the white dock */
  .dock__label{ display:none; }
  .dock{ padding:8px; }
  .foot__cols{ grid-template-columns:1fr; gap:26px; }
  /* Carousel on a phone — tighter controls so the ticks + arrows never crowd
     the narrow bottom row. */
  .carousel__caption{ max-width:26ch; }
  .carousel__tick span{ width:22px; }
  .carousel__arrow{ width:44px; height:44px; font-size:22px; }
  /* §01/§02 frame on a phone. The photos are wide group shots (2.2:1) and the
     clips are 16/9; a tall frame would keep barely a third of a panorama and
     cut the people at the edges off, a frame the full width of the source
     leaves dead bars above and below. The budget is 10% off each side and
     nothing off the top or bottom — for a 2.2:1 source that is exactly 16/9,
     and cropping those sides zooms the picture in 25%, which is what makes it
     bigger. The 16/9 clips land in it untouched. */
  .quefem__carousel,
  .quisom__carousel{
    height:auto;
    aspect-ratio:16/9;
    /* the only two blocks that break the page gutters: at 10% the frame ratio
       is fixed, so screen width is the only thing left that makes the picture
       bigger. html/body already clip overflow-x. */
    width:100vw;
    margin-inline:calc(50% - 50vw);
    border-radius:0;
  }
  .quisom__carousel .carousel__overlay{ padding-bottom:12px; }
  /* §06 goes full-bleed like its siblings. There is no room beside a 100vw
     frame, so the arrows drop under it and bracket the ticks. */
  .curts__frame{
    grid-column:1 / -1;
    width:100vw;
    margin-inline:calc(50% - 50vw);
    border-radius:0;
  }
  .curts__arrow--prev{ grid-column:1; grid-row:2; }
  .curts__ticks{ grid-column:2; grid-row:2; }
  .curts__arrow--next{ grid-column:3; grid-row:2; }
  /* shorter frame, shorter controls row — the notes follow both down */
  .slide-note{
    font-size:1.5rem;
    max-width:min(20ch,90%);
    --note-edge:14px;
    --note-floor:84px;   /* clears the arrows AND the counter to their left */
  }
}

/* === §04 map ============================================================
   The engraving is square, so .mapfig__frame locks 1/1 and every marker is
   positioned in % of it — the two layers can never drift apart. Above 760px
   the popover is a small card anchored to its marker; below, the same markup
   is re-parented into a bottom sheet. One .mapop, moved, not two built. */
/* The engraving is square and mostly sea, so at full column width it would be
   a 1200px-tall block. Capped, it sits as a plate with air around it. */
.mapfig{ position:relative; max-width:860px; margin-inline:auto; }
.mapfig__frame{
  position:relative;
  aspect-ratio:1/1;
  border-radius:var(--radius);
  overflow:hidden;
  background:var(--bg-raised);
}
.mapfig__frame img{ width:100%; height:100%; object-fit:cover; display:block; }
.mapfig__markers{ position:absolute; inset:0; }
.mapfig__caption{ margin-top:var(--gap); color:var(--fg-mute); }

/* Marker: crossed swords on a 44px transparent tap target, so thumbs get their
   minimum without the icon having to be thumb-sized. The swords are a mask,
   not an <img>: the shape comes from the artwork, the colour from the palette,
   so it stays legible against the pale engraving at 24px. */
.mapmark{
  position:absolute;
  width:44px; height:44px;
  margin:-22px 0 0 -22px;
  display:grid; place-items:center;
  background:none; border:0; padding:0;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
/* Without mask support this would be a solid black square, so the swords are
   an upgrade over a plain dot rather than the base case. */
.mapmark__dot{
  width:10px; height:10px;
  border-radius:50%;
  background:var(--bg);
  transition:transform var(--dur) var(--ease);
}
@supports ((mask-image:url('')) or (-webkit-mask-image:url(''))){
  .mapmark__dot{
    width:24px; height:24px;
    border-radius:0;
    -webkit-mask:url('/assets/img/mapa/swords-mask.png') center / contain no-repeat;
            mask:url('/assets/img/mapa/swords-mask.png') center / contain no-repeat;
  }
}

/* Labels are always on — the point of the map is to see where we have been
   without having to go looking for it. Solid ground behind them, because the
   engraving is pale and busy with its own retolat. `dir` fans them out so the
   two inland pairs do not sit on top of each other. */
.mapmark__label{
  position:absolute; top:50%; left:50%;
  transform:translate(16px,-50%);
  white-space:nowrap;
  padding:3px 6px;
  background:var(--bg);
  color:var(--fg);
  cursor:pointer;
  transition:background var(--dur) var(--ease);
}
/* The name is a hover target in its own right — it is the largest thing the
   marker has, and aiming for a 24px pair of swords to see the photos is a
   worse deal than aiming for the word next to them. */
.mapmark:hover .mapmark__label,
.mapmark:focus-visible .mapmark__label,
.mapmark.is-open .mapmark__label{ background:var(--bg-raised); }
.mapmark--lw .mapmark__label{ left:auto; right:50%; transform:translate(-16px,-50%); }
.mapmark--ln .mapmark__label{ top:auto; bottom:50%; transform:translate(-50%,-14px); }
.mapmark--ls .mapmark__label{ transform:translate(-50%,14px); }

.mapmark:hover .mapmark__dot,
.mapmark:focus-visible .mapmark__dot,
.mapmark.is-open .mapmark__dot{ transform:scale(1.2); }
.mapmark:focus-visible{ outline:1px solid var(--bg); outline-offset:2px; }

/* Popover — desktop card. Anchored by initMap; --mx/--my are the marker's
   position in % of the frame, flipped by .mapop--w / .mapop--s at the edges. */
.mapop{
  position:absolute;
  z-index:3;
  width:300px; max-width:calc(100vw - var(--pad) * 2);
  left:var(--mx); top:var(--my);
  /* --vshift is written by initMap once the card has been measured: it is the
     correction that keeps a card near the top or bottom edge inside the frame.
     The extra 8px is the reveal travel, removed by .is-open. */
  --vshift:0px;
  transform:translate(18px,-50%) translateY(calc(var(--vshift) + 8px));
  background:var(--bg-raised);
  border:1px solid var(--line-strong);
  opacity:0; visibility:hidden;
  transition:opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
}
.mapop.is-open{ opacity:1; visibility:visible; transform:translate(18px,-50%) translateY(var(--vshift)); }
.mapop--w{ transform:translate(calc(-100% - 18px),-50%) translateY(calc(var(--vshift) + 8px)); }
.mapop--w.is-open{ transform:translate(calc(-100% - 18px),-50%) translateY(var(--vshift)); }
.mapop--s{ transform:translate(-50%,18px) translateY(calc(var(--vshift) + 8px)); }
.mapop--s.is-open{ transform:translate(-50%,18px) translateY(var(--vshift)); }

.mapop__head{
  display:grid; grid-template-columns:1fr auto; align-items:start; gap:var(--gap);
  padding:14px var(--gap) 10px;
}
.mapop__title{ font-size:var(--step-1); letter-spacing:-.02em; line-height:1.1; }
.mapop__note{ color:var(--fg-dim); font-size:var(--step-0); margin-top:4px; }
.mapop__meta{ color:var(--fg-mute); margin-top:8px; }
.mapop__close{
  width:32px; height:32px; margin:-4px -4px 0 0;
  display:grid; place-items:center;
  background:none; border:0; padding:0; cursor:pointer;
  color:var(--fg-mute);
  transition:color var(--dur) var(--ease);
}
.mapop__close:hover{ color:var(--fg); }
.mapop__close svg{ width:13px; height:13px; stroke:currentColor; stroke-width:1.5; fill:none; }

/* Popover carousel — its own small implementation, not initCarousel: no
   video, no embeds, no autoplay. Fixed 4/3 cells, so no shift as it pages. */
.mapcar{ position:relative; }
.mapcar__viewport{ position:relative; aspect-ratio:4/3; overflow:hidden; background:var(--bg); }
/* Stacked slides are transparent but still hit-testable, so without this the
   last one in the DOM would swallow every click and zoom the wrong photo. */
.mapcar__slide{
  position:absolute; inset:0;
  opacity:0; pointer-events:none;
  transition:opacity var(--dur) var(--ease);
}
.mapcar__slide.is-active{ opacity:1; pointer-events:auto; }
.mapcar__slide.is-zoomable{ cursor:zoom-in; }
.mapcar__slide img{ width:100%; height:100%; object-fit:cover; display:block; filter:saturate(.8); }
.mapcar__bar{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:var(--gap);
  padding:10px var(--gap) 12px;
}
.mapcar__index{ color:var(--fg-mute); }
.mapcar__ticks{ display:flex; align-items:center; justify-content:center; gap:8px; }
.mapcar__tick{
  width:20px; height:1px; padding:9px 0; background:none; border:0; cursor:pointer;
  position:relative;
}
.mapcar__tick::after{
  content:''; position:absolute; inset:9px 0; background:var(--line-strong);
  transition:background var(--dur) var(--ease);
}
.mapcar__tick.is-active::after{ background:var(--fg); }
.mapcar__arrows{ display:flex; gap:6px; }
.mapcar__arrow{
  width:26px; height:26px; display:grid; place-items:center;
  background:none; border:1px solid var(--line); padding:0; cursor:pointer;
  color:var(--fg-dim);
  transition:color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.mapcar__arrow:hover{ color:var(--fg); border-color:var(--line-strong); }
.mapcar__arrow svg{ width:9px; height:9px; stroke:currentColor; stroke-width:1.6; fill:none; }
.mapcar--single .mapcar__bar{ grid-template-columns:1fr; }
.mapcar--single .mapcar__ticks,
.mapcar--single .mapcar__arrows{ display:none; }

/* Backdrop — mobile only, but declared here so the hidden state is shared. */
.mapsheet__backdrop{
  position:fixed; inset:0; z-index:40;
  background:var(--scrim);
  opacity:0; transition:opacity var(--dur) var(--ease);
}
.mapsheet__backdrop.is-open{ opacity:1; }

/* The dock is fixed bottom-right, exactly where the sheet puts its carousel
   controls. While a sheet is open the dock stands down — the × and the
   backdrop are the actions on offer, and the dock is one scroll away. */
.map-sheet-open .dock{ opacity:0; pointer-events:none; }

/* Mobile: the popover leaves the map and becomes a bottom sheet that nearly
   covers it. Backdrop and the × both close it. */
@media (max-width:760px){
  /* The map is panned at 260% here, so the labels have the room to stay on —
     and they are the reason the section works without any interaction. */

  /* At phone width the whole island is ~350px across, which puts Mancor and
     Inca 19px apart — closer than one thumb, so the nearer marker swallows
     the other. The map is therefore drawn larger than the window and panned
     inside it. 1.8× is the zoom-out limit: it shows a bit over half the plate
     at once while still holding those two ~35px apart, which keeps each dot
     on its own tap target. Below ~1.5× they start fighting again. */
  .mapfig__scroll{
    overflow:auto;
    max-height:78svh;
    border-radius:var(--radius);
    overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;
  }
  .mapfig__frame{ width:180%; border-radius:0; }
  .mapop{
    position:fixed; z-index:41;
    left:0; right:0; top:auto; bottom:0;
    width:auto; max-width:none;
    max-height:85svh; overflow-y:auto;
    border:0; border-top:1px solid var(--line-strong);
    transform:translateY(100%);
  }
  .mapop.is-open,
  .mapop--w.is-open,
  .mapop--s.is-open{ transform:translateY(0); }
  .mapop--w,.mapop--s{ transform:translateY(100%); }
  .mapop__head{ padding:18px var(--pad) 12px; }
  .mapop__close{ width:44px; height:44px; margin:-8px -12px 0 0; }
  .mapcar__bar{ padding:12px var(--pad) 24px; }
}

/* === reduced motion (§5) ================================================ */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
  .reveal{ opacity:1; transform:none; }
  .hero__cue span{ animation:none; }
}
