/* ============================================================
   GRAPHICXO — CASE STUDY  (project.php, /work/{slug})

   Loaded after portfolio.css, which already supplies .pglow and
   the wall's plate treatment. This file is only the page that
   shows ONE project.

   Everything colour here reads --accent / --accent-rgb off .pj,
   set inline from the project's own accent. Nothing below hard-
   codes a hue except the neutrals, so twenty projects share one
   stylesheet and none of them look like each other.

   Hover rules live inside @media (hover:hover) — see the note at
   the top of main.css.
   ============================================================ */

.pj{position:relative;z-index:1}

/* ------------------------------------------------------------
   HEAD
   ------------------------------------------------------------ */
.pj-head{
  position:relative;
  padding-top:clamp(8rem,16vh,12rem);
  padding-bottom:clamp(2rem,5vh,3.5rem);
}
.pj-head__back{margin-bottom:clamp(2rem,5vh,3rem)}
.pj-head__back a{
  display:inline-flex;align-items:center;gap:.55rem;
  font-size:.8rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey-dim);
  transition:color .35s var(--ease),gap .35s var(--ease);
}
@media (hover:hover){
  .pj-head__back a:hover{color:var(--accent);gap:.9rem}
}

.pj-head__title{
  font-size:clamp(2.6rem,8vw,7rem);
  line-height:.98;letter-spacing:-.03em;
  max-width:16ch;
}
/* Masked line-rise, the same device the other page heads use, so a
   case study opens like the rest of the site rather than like a
   document. */
/* .is-in, not .in — [data-rise] is driven by each page's own script and
   uses is-in throughout the project; .reveal is the app.js-wide one that
   uses .in. Two conventions, and mixing them means the title never
   arrives. Padding keeps the overflow off the descenders. */
.pj-head__mask{display:block;overflow:hidden;padding-bottom:.08em}
.pj-head__mask>span{display:block;transform:translateY(115%);transition:transform 1.05s var(--ease)}
.pj-head__title.is-in .pj-head__mask>span{transform:none}

.pj-head__tags{
  list-style:none;display:flex;flex-wrap:wrap;gap:.5rem;
  margin-top:1.6rem;
}
.pj-head__tags li{
  font-size:.72rem;font-weight:600;letter-spacing:.18em;text-transform:uppercase;
  color:var(--accent);
  padding:.45rem .9rem;
  border:1px solid rgba(var(--accent-rgb),.34);
  border-radius:100px;
  background:rgba(var(--accent-rgb),.07);
}

/* The spec strip. A definition list because that is what it is —
   label and value — and a screen reader then reads the pairing
   rather than six loose words. */
.pj-spec{
  display:flex;flex-wrap:wrap;gap:2.4rem 3.5rem;
  margin-top:clamp(2.4rem,5vh,3.4rem);
  padding-top:1.8rem;
  border-top:1px solid var(--line);
}
.pj-spec__row{display:flex;flex-direction:column;gap:.45rem;min-width:0}
.pj-spec dt{
  font-size:.68rem;font-weight:600;letter-spacing:.22em;text-transform:uppercase;
  color:var(--grey-dim);
}
.pj-spec dd{font-size:.98rem;color:var(--white);font-weight:300}

/* ------------------------------------------------------------
   THE PLATE — the mark, at size
   ------------------------------------------------------------ */
.pj-plate{margin-top:clamp(2rem,5vh,3.5rem)}
.pj-plate__frame{
  position:relative;
  display:grid;place-items:center;
  /* A fixed band rather than "whatever height the file is". The sources
     are A4 sheets, 1080 squares and 16:9 stills; left to size themselves
     at full width an A4 hero runs 1800px tall, which is more than two
     viewports and means the reveal never fires above the fold. Contained
     inside a set band, every project opens the same way and the artwork
     keeps its own aspect. */
  height:min(78svh,880px);
  padding:clamp(1rem,3vw,2.6rem);
  border-radius:18px;
  overflow:hidden;
  border:1px solid rgba(var(--accent-rgb),.22);
  /* The accent bleeds out from under the plate rather than being
     painted on it — the artwork keeps its own colours intact. */
  box-shadow:0 40px 120px -50px rgba(var(--accent-rgb),.75),
             0 2px 60px -30px rgba(var(--accent-rgb),.5);
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(var(--accent-rgb),.10), transparent 62%),
    #0a0a0a;
}
.pj-plate__frame img{
  display:block;
  max-width:100%;max-height:100%;
  width:auto;height:auto;
  object-fit:contain;
  border-radius:6px;
}

/* ------------------------------------------------------------
   SECTION HEADS
   ------------------------------------------------------------ */
.pj-sec__title{
  font-family:var(--serif);
  font-size:clamp(1.6rem,3.4vw,2.6rem);
  letter-spacing:-.02em;
  margin-bottom:1.4rem;
}
.pj-pal,.pj-read,.pj-film,.pj-gal{padding-block:clamp(3.5rem,9vh,7rem)}

/* ------------------------------------------------------------
   PALETTE
   The centre of the page. Each cell is a tall column that grows
   on hover, so the row behaves like a set of paint chips being
   pulled out rather than a bar chart.
   ------------------------------------------------------------ */
.pj-pal__head{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:.6rem 1.6rem;
  margin-bottom:1.8rem;
}
.pj-pal__head .pj-sec__title{margin-bottom:0}
.pj-pal__note{color:var(--grey-dim);font-size:.9rem;font-weight:300;max-width:44ch}

.pj-pal__row{
  list-style:none;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
  gap:.6rem;
}
.pj-pal__cell{
  /* The swatch is the cell's background; the chip inside is the
     hit target and the label. */
  border-radius:14px;
  overflow:hidden;
  background:var(--sw);
  border:1px solid rgba(255,255,255,.10);
  transition:transform .45s var(--ease),box-shadow .45s var(--ease);
  /* Staggered off --i so the row assembles left to right when the
     section reveals, instead of all at once. */
  transition-delay:calc(var(--i) * 40ms);
}
.pj-pal__chip{
  display:flex;align-items:flex-end;
  width:100%;height:clamp(120px,17vw,190px);
  padding:.9rem;
  background:none;border:0;
  cursor:pointer;
}
.pj-pal__hex{
  font-family:var(--sans);
  font-size:.78rem;font-weight:600;letter-spacing:.08em;
  /* Default is a light label on a dark swatch. .is-light flips it —
     the decision is made in project_palette() from the colour's own
     relative luminance, not guessed here. */
  color:rgba(255,255,255,.92);
  text-shadow:0 1px 10px rgba(0,0,0,.45);
  transition:transform .35s var(--ease);
}
.pj-pal__cell.is-light .pj-pal__hex{
  color:rgba(0,0,0,.78);
  text-shadow:0 1px 10px rgba(255,255,255,.35);
}
@media (hover:hover){
  .pj-pal__cell:hover{
    transform:translateY(-6px);
    box-shadow:0 22px 50px -22px rgba(var(--sw-rgb),.9);
  }
  .pj-pal__cell:hover .pj-pal__hex{transform:translateY(-2px)}
}
.pj-pal__chip:focus-visible{outline:2px solid var(--gold-soft);outline-offset:-4px}

.pj-pal__live{
  margin-top:1rem;min-height:1.2em;
  font-size:.82rem;color:var(--accent);
  opacity:0;transition:opacity .3s;
}
.pj-pal__live.is-on{opacity:1}

/* ------------------------------------------------------------
   THE READ
   ------------------------------------------------------------ */
.pj-read__body{max-width:68ch}
.pj-read__body p{
  color:var(--grey);
  font-size:clamp(1rem,1.25vw,1.12rem);
  font-weight:300;
  line-height:1.85;
}
.pj-read__body p + p{margin-top:1.5rem}
.pj-read__body strong{color:var(--white);font-weight:600}
.pj-read__body em{color:var(--accent);font-style:italic}

/* ------------------------------------------------------------
   FILM
   ------------------------------------------------------------ */
.pj-film__stage{
  position:relative;
  border-radius:16px;
  overflow:hidden;
  border:1px solid rgba(var(--accent-rgb),.2);
  box-shadow:0 40px 110px -55px rgba(var(--accent-rgb),.8);
  background:#000;
}
.pj-film__video{display:block;width:100%;height:auto}

/* A vertical reel — a phone-shaped clip — is capped so it does not
   run past the fold on a laptop. */
.pj-film__stage.is-reel{max-width:420px;margin-inline:auto}

/* The site walkthroughs are 1280x720 screen recordings carrying
   57px of letterbox at the top, ~124px of letterbox plus the
   recorder toolbar at the bottom, and a 14px scrollbar on the
   right. The live page area is x 0-1266, y 57-596.

     wrapper aspect = 1266 / 539
     video width    = 1280 / 1266 = 101.1% of the wrapper
     video offset   = -57 / 539   = -10.57% of the wrapper height

   Cropping in CSS rather than re-encoding because there is no
   ffmpeg on the build machine — and because the source files stay
   untouched either way. */
.pj-film__stage.is-cropped{
  aspect-ratio:1266/539;
  /* The already-cropped poster, sized to the stage. Set inline by
     project.php; these are the rules that make it behave. */
  background-size:cover;
  background-position:center;
  background-repeat:no-repeat;
}
.pj-film__stage.is-cropped .pj-film__video{
  position:absolute;
  top:-10.57%;left:0;
  width:101.1%;
  height:auto;
}
/* Controls sit at the bottom of the video element, which the crop
   pushes out of view. Give the stage its own play affordance. */
.pj-film__stage.is-cropped .pj-film__video::-webkit-media-controls{display:none}

/* project.js strips the video's own controls on a cropped stage —
   they sit below the crop line and cannot be reached — and appends
   this instead. Centred, fades out while the clip is running. */
.pj-film__play{
  position:absolute;inset:0;
  display:grid;place-items:center;
  width:100%;height:100%;
  background:linear-gradient(180deg,rgba(0,0,0,.05),rgba(0,0,0,.45));
  color:var(--white);
  cursor:pointer;
  transition:opacity .4s var(--ease);
}
.pj-film__play svg{width:34px;height:34px;position:relative;z-index:2;translate:3px 0}
.pj-film__play-ring{
  position:absolute;
  width:82px;height:82px;border-radius:50%;
  border:1px solid rgba(255,255,255,.5);
  background:rgba(var(--accent-rgb),.22);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  transition:transform .45s var(--ease),background .45s var(--ease),border-color .45s var(--ease);
}
@media (hover:hover){
  .pj-film__play:hover .pj-film__play-ring{
    transform:scale(1.08);
    background:rgba(var(--accent-rgb),.5);
    border-color:var(--accent);
  }
}
.pj-film__play:focus-visible{outline:2px solid var(--gold-soft);outline-offset:-6px}
/* While it plays the overlay gets out of the way, but stays clickable
   so the whole frame is a pause target. */
.pj-film__stage.is-playing .pj-film__play{opacity:0}
@media (hover:hover){
  .pj-film__stage.is-playing:hover .pj-film__play{opacity:1}
}

/* ------------------------------------------------------------
   GALLERY
   ------------------------------------------------------------ */
.pj-gal__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:1rem;
}
.pj-gal__item{
  border-radius:14px;overflow:hidden;
  border:1px solid var(--line);
  background:#0b0b0b;
  transition:border-color .4s var(--ease),transform .5s var(--ease);
}
.pj-gal__item img{display:block;width:100%;height:100%;object-fit:cover;aspect-ratio:1/1}

/* ---- A site's gallery ----
   Page sections, not applications. They arrive at whatever height the
   scroll gave — 1347x345 for a strip, 1347x678 for a full view — and the
   square tiles above were cropping a wide strip down to a square of its
   middle. One column, full width, natural height: the image decides its
   own shape and nothing is cut. */
.pj-gal--web .pj-gal__grid{grid-template-columns:1fr;gap:clamp(1rem,2.4vw,1.8rem)}
.pj-gal--web .pj-gal__item img{
  height:auto;
  aspect-ratio:auto;
  object-fit:contain;
}
@media (hover:hover){
  .pj-gal__item:hover{border-color:rgba(var(--accent-rgb),.5);transform:translateY(-4px)}
}

/* ------------------------------------------------------------
   PAGER
   Each side wears the colour of the project it leads to, so the
   next piece of work announces itself before you arrive.
   ------------------------------------------------------------ */
.pj-pager{
  display:grid;grid-template-columns:1fr 1fr;gap:1rem;
  padding-block:clamp(3rem,7vh,5rem);
  border-top:1px solid var(--line);
}
.pj-pager__side{
  --accent-rgb:255,255,255;
  display:flex;flex-direction:column;gap:.5rem;
  padding:clamp(1.4rem,3vw,2.2rem);
  border:1px solid var(--line);
  border-radius:16px;
  transition:border-color .4s var(--ease),background .4s var(--ease),transform .4s var(--ease);
}
.pj-pager__side--next{text-align:right;grid-column:2}
.pj-pager__dir{
  font-size:.68rem;font-weight:600;letter-spacing:.22em;text-transform:uppercase;
  color:var(--grey-dim);
}
.pj-pager__name{
  font-family:var(--serif);
  font-size:clamp(1.2rem,2.6vw,1.9rem);
  color:var(--white);
  transition:color .4s var(--ease);
}
@media (hover:hover){
  .pj-pager__side:hover{
    border-color:var(--accent);
    background:color-mix(in srgb, var(--accent) 8%, transparent);
    transform:translateY(-3px);
  }
  .pj-pager__side:hover .pj-pager__name{color:var(--accent)}
}

/* ------------------------------------------------------------
   NARROW
   ------------------------------------------------------------ */
@media (max-width:820px){
  .pj-spec{gap:1.6rem 2.2rem}
  .pj-pal__row{grid-template-columns:repeat(auto-fit,minmax(92px,1fr))}
  .pj-pal__chip{height:104px}
  .pj-pager{grid-template-columns:1fr}
  .pj-pager__side--next{grid-column:1;text-align:left}
}

@media (prefers-reduced-motion:reduce){
  .pj-head__mask>span{transform:none;transition:none}
  .pj-pal__cell{transition-delay:0s}
  @media (hover:hover){
    .pj-pal__cell:hover,.pj-gal__item:hover,.pj-pager__side:hover{transform:none}
  }
}

/* The live-site link in the spec strip. Underlined on the accent rather
   than coloured, so it reads as a link without competing with the tags. */
.pj-spec__link{
  color:var(--white);
  border-bottom:1px solid rgba(var(--accent-rgb),.5);
  padding-bottom:1px;
  transition:color .35s var(--ease),border-color .35s var(--ease);
}
@media (hover:hover){
  .pj-spec__link:hover{color:var(--accent);border-color:var(--accent)}
}
