/*
Theme Name: Campolo
Description: Personal portfolio theme for Carlo Alberto Campolo — print-sheet minimalism with an orange accent. Four sections: home, works (split index), journal, contact.
Author: Carlo Alberto Campolo
Version: 1.5.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: campolo
*/

@font-face{
  font-family:"Overused Grotesk";
  src:url("fonts/OverusedGrotesk-VF.ttf") format("truetype-variations");
  font-weight:300 900;
  font-display:swap;
}

:root{
  --ground:#F1EEE7;
  --ink:#16150F;
  --grey:#8B887E;
  --hair:#D8D3C6;
  --accent:#F2561D;
  --sans:"Overused Grotesk","Helvetica Neue",Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  --adminbar:0px;
}
body.admin-bar{--adminbar:32px}
@media(max-width:782px){ body.admin-bar{--adminbar:46px} }
*{box-sizing:border-box;margin:0}
html{scroll-behavior:smooth}
body{background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased;
     display:flex;flex-direction:column;min-height:calc(100vh - var(--adminbar))}
a{color:inherit;text-decoration:none}
img{max-width:100%;height:auto;display:block}
button{font:inherit;color:inherit;cursor:pointer}
::selection{background:var(--accent);color:var(--ground)}
@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}html{scroll-behavior:auto}}

.lbl{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--grey)}
.lbl b{font-weight:400;color:var(--accent)}

/* ---------- chrome ---------- */
.site-nav{position:fixed;inset:0 0 auto;display:flex;justify-content:space-between;align-items:baseline;padding:20px 28px;z-index:10;background:linear-gradient(var(--ground) 60%,transparent)}
.brand{font-weight:700;letter-spacing:.02em;font-size:15px;line-height:1.2}
.brand i{font-style:normal;color:var(--accent)}
.brand small{display:block;font-family:var(--sans);font-size:15px;letter-spacing:.02em;color:var(--grey);font-weight:400;margin-top:2px}
.site-nav .links{display:flex;gap:26px}
.site-nav .links a{font-family:var(--mono);font-size:11.5px;font-weight:600;letter-spacing:.16em;color:var(--grey);transition:color .15s}
.site-nav .links a:hover{color:var(--ink)}
.site-nav .links a.on{color:var(--ink)}
.site-nav .links a.on::before{content:"";display:inline-block;width:7px;height:7px;background:var(--accent);margin-right:8px;vertical-align:1px}

.burger{display:none;background:none;border:0;font-family:var(--mono);font-size:16px;font-weight:600;color:var(--ink);padding:6px 0;align-items:center}
.burger .sq{display:inline-block;width:11px;height:11px;background:var(--accent);margin:0 8px;transition:transform .2s,background .2s}
.burger[aria-expanded="true"] .sq{transform:rotate(45deg);background:var(--ink)}
.menu{display:none}

/* margin-top:auto absorbs any leftover vertical space, so the footer sits at the
   bottom of the viewport on short pages without pushing itself below the fold.
   flex-shrink:0 keeps it at its natural height when a sibling (the works pane)
   is competing for the same flex line. */
.site-footer{padding:16px 28px;border-top:1px solid var(--hair);display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-top:auto;flex-shrink:0}

/* ---------- home ---------- */
/* Scoped to the element deliberately: WordPress puts a `home` class on <body>
   for the front page, so a bare `.home` selector matches the body too — which
   duplicated this padding and left 60px hanging below the footer. */
section.home{display:flex;flex-direction:column;min-height:calc(100vh - var(--adminbar));padding:0 28px 60px}
.tagline{position:relative;min-height:calc(100vh - var(--adminbar));display:flex;flex-direction:column;justify-content:center;gap:.55em;
         font-size:clamp(30px,4.7vw,74px);font-weight:500;letter-spacing:-.02em;line-height:1.12}
.tagline p{max-width:19em}
.tagline .hl{padding:.02em .14em .05em;margin-left:-.14em;-webkit-box-decoration-break:clone;box-decoration-break:clone;transition:background .15s,color .15s}
.tagline .hl:hover,.tagline .hl.on{background:var(--accent);color:#F8F5EF}
.scrollcue{display:none}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(6px)}}
.home-rows{border-top:1px solid var(--hair);margin-top:2vh}
.row{display:grid;grid-template-columns:56px 1fr auto;align-items:baseline;gap:24px;padding:16px 0;border-bottom:1px solid var(--hair);transition:padding .15s}
.row:hover{padding-left:10px}
.row .no{font-family:var(--mono);font-size:11px;color:var(--grey)}
.row:hover .no{color:var(--accent)}
.row h3{font-size:22px;font-weight:400;letter-spacing:-.01em}
.row .cat{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey)}

/* ---------- works : split 1/4 ----------
   No fixed height here any more. The body is a flex column of exactly two
   children — this pane and the footer — so `flex:1 1 0` makes the pane take
   the viewport minus whatever the footer needs, and the footer lands on the
   bottom edge with no page scroll behind it.

   `flex-basis:0` rather than `auto` is the load-bearing part: with `auto` the
   pane's base size is its full content height, so a long project list would
   push the footer far below the fold again. `min-height:0` is required
   alongside it, because a flex item's automatic minimum size would otherwise
   clamp the pane back up to its content height and undo the basis. */
.works{display:grid;grid-template-columns:1fr 4fr;padding-top:64px;flex:1 1 0;min-height:0}
.works-list{border-right:1px solid var(--hair);padding:26px 22px;display:flex;flex-direction:column;min-height:0;overflow-y:auto}
.works-list .lbl{margin-bottom:22px}
.works-list a{display:grid;grid-template-columns:30px 1fr;gap:10px;padding:10px 0;font-size:14px;color:var(--grey);transition:color .15s}
.works-list a .no{font-family:var(--mono);font-size:10px;padding-top:3px}
.works-list a:hover{color:var(--ink)}
.works-list a.on{color:var(--ink)}
.works-list a.on .no{color:var(--accent)}
.works-list .foot{margin-top:auto}
/* min-height:0 for the same reason as above, one level down: grid items also
   get an automatic minimum size, which would stop this pane shrinking below
   its content and so stop `overflow-y:auto` ever producing a scrollbar. */
.works-scroll{overflow-y:auto;min-height:0;padding:26px 34px 80px;scroll-behavior:smooth}
.proj{padding:22px 0 56px;border-bottom:1px solid var(--hair)}
.proj:last-child{border-bottom:0}
.proj header{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:18px;gap:20px;flex-wrap:wrap}
.proj h2{font-size:34px;font-weight:400;letter-spacing:-.015em}
/* --row-h is the height a justified row aims for, not a fixed height: it is the
   point at which main.js decides a row is full and starts a new one. --row-max
   is the hard ceiling. Only the last row of a gallery can ever reach it — every
   earlier row closes at or below --row-h — and a row held at the ceiling keeps
   its proportions and stops short of the right edge rather than growing to
   meet it. Both are read back by main.js; tune them here. */
.proj-content{max-width:none;--row-h:280px;--row-max:535px}
.proj-content p{max-width:44em;margin-top:16px;color:#3B3A33}
/* box-shadow, not border: a border is inside the box under box-sizing, so a
   1px rule stole 2px from every image's content area. Widths are computed from
   the images' own proportions, and that 2px made each one land at a slightly
   different height and pushed the row a fraction over the container width —
   enough to wrap the last image onto a line of its own. A shadow paints
   outside the box and takes no space at all. */
.proj-content img{box-shadow:0 0 0 1px var(--hair);width:100%}
.proj-content figure{margin:0}
.proj-content figcaption{font-family:var(--mono);font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--grey);margin-top:6px}

/* ---------- project images ----------
   One shared height across the row; each image keeps its own proportions and
   takes whatever width that implies. Nothing is cropped or letterboxed.

   Selectors carry deliberate extra specificity. Core ships
   `.wp-block-gallery.is-layout-flex` and
   `.wp-block-gallery.has-nested-images figure.wp-block-image` with its own
   display, gap and percentage widths. Those tie a plainer selector and win on
   source order — which is what collapsed the gap to 7.5px and re-flowed the
   row. Matching class counts is what makes these hold. */
.proj-content .wp-block-gallery,
.proj-content .wp-block-gallery.is-layout-flex,
.proj-content .wp-block-gallery .blocks-gallery-grid,
.proj-content .gallery,
.proj-content p:has(img ~ img),
.proj-content p:has(picture ~ picture){
  --wp--style--unstable-gallery-gap:14px;
  display:flex;
  flex-wrap:wrap;
  align-items:flex-start;
  gap:14px;
  margin-top:6px;
  max-width:none;
  padding:0;
  list-style:none;
}

/* Items are sized by their image, so core's percentage widths and any flex
   sizing must be neutralised. */
/* `:not(#_)` is a specificity bump, not a filter — it matches everything, since
   nothing has id="_". Core sets its column widths with
   `figure.wp-block-image:not(#individual-image)`, which puts an ID in the
   selector (1,4,2). No class-only selector can outrank that however long it is,
   so figures kept core's `width:calc(33.33% - gap)`, every image was forced to
   an equal column width, and object-fit then cropped them to fit. This matches
   core's trick to reclaim the cascade.
   `display:block` matters too: core makes the figure a column flex box, and a
   stretched flex child ignores `width:auto` and fills the cross axis. */
.proj-content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#_),
.proj-content .wp-block-gallery.has-nested-images.is-layout-flex figure.wp-block-image:not(#_),
.proj-content .wp-block-gallery .wp-block-image:not(#_),
.proj-content .wp-block-gallery .blocks-gallery-item:not(#_),
.proj-content .gallery .gallery-item:not(#_){
  display:block;
  flex:0 0 auto;
  align-self:flex-start;
  width:auto;
  max-width:100%;
  margin:0;
}

/* Shared height, natural width. object-fit only comes into play if max-width
   clamps an unusually wide image. */
.proj-content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#_) img,
.proj-content .wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#_) img,
.proj-content .wp-block-gallery .wp-block-image:not(#_) img,
.proj-content .wp-block-gallery .blocks-gallery-item:not(#_) img,
.proj-content .gallery .gallery-item:not(#_) img,
.proj-content p:has(img ~ img) > img,
.proj-content p:has(picture ~ picture) img{
  height:var(--row-h);
  width:auto;
  max-width:100%;
  object-fit:cover;
  display:block;
}

.proj-content .wp-block-image{margin-top:14px}
.proj-content .gallery .gallery-icon{margin:0;line-height:0}
.proj-content .gallery .gallery-caption{font-family:var(--mono);font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--grey);margin-top:6px}
.proj-content p:has(picture ~ picture) picture{display:block}

.proj .tags{display:flex;gap:8px;margin-top:14px;flex-wrap:wrap}
.proj .tags span{font-family:var(--mono);font-size:10px;letter-spacing:.1em;border:1px solid var(--hair);padding:4px 9px;color:var(--grey)}

/* ---------- journal ---------- */
.journal{max-width:900px;padding:130px 28px 90px;margin:0 auto}
.journal>.lbl{display:block;margin-bottom:34px}
.entry{display:grid;grid-template-columns:160px 1fr;gap:14px 40px;padding:26px 0;border-top:1px solid var(--hair)}
.entry:last-of-type{border-bottom:1px solid var(--hair)}
.entry time{font-family:var(--mono);font-size:10px;letter-spacing:.14em;color:var(--grey);padding-top:6px}
.entry h3{font-size:21px;font-weight:400;margin-bottom:8px}
.entry h3 a:hover{color:var(--accent)}
.entry .body p{color:#3B3A33;max-width:40em;margin-bottom:.8em}
.entry .body img{border:1px solid var(--hair);margin:10px 0}
.entry .kind{font-family:var(--mono);font-size:9px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);display:block;margin-bottom:6px}
.pagination{display:flex;gap:18px;margin-top:34px}
.pagination a{font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.14em;color:var(--grey)}
.pagination a:hover{color:var(--ink)}

/* ---------- contact ---------- */
.contact{display:flex;flex-direction:column;min-height:calc(100vh - var(--adminbar));padding:90px 28px 28px}
.contact .big{font-size:clamp(34px,6.4vw,92px);font-weight:500;letter-spacing:-.03em;line-height:1.02;max-width:12em;margin-top:auto}
.contact .rows{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin:auto 0}
.contact .rows a{font-family:var(--mono);font-size:18px;font-weight:600;letter-spacing:.14em;color:var(--ink);
                 padding:10px 12px;margin-left:-12px;transition:background .15s,color .15s}
.contact .rows a:hover{background:var(--accent);color:#F8F5EF}
.contact .corners{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap;border-top:1px solid var(--hair);padding-top:18px}
.contact .clock{font-variant-numeric:tabular-nums}

/* ---------- generic page / single ---------- */
.sheet-page{max-width:900px;margin:0 auto;padding:130px 28px 90px}
.sheet-page h1{font-size:34px;font-weight:400;letter-spacing:-.015em;margin-bottom:22px}
.sheet-page .content p{max-width:44em;color:#3B3A33;margin-bottom:.9em}
.backlink{font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.14em;color:var(--grey);display:inline-block;margin-bottom:26px}
.backlink:hover{color:var(--ink)}

/* ---------- kill drag-to-save and long-press-to-save (iOS) ---------- */
.proj-content img,
.entry .body img,
.wp-block-image img {
	-webkit-user-drag: none;
	-webkit-touch-callout: none;   /* iOS "Save Image" on long press */
	user-select: none;
}

/* ---------- mobile ---------- */
@media(max-width:820px){
  .site-nav{z-index:30}
  .site-nav .links{display:none}
  .burger{display:flex}
  .menu.open{display:flex;position:fixed;inset:0;background:var(--ground);z-index:25;flex-direction:column;justify-content:center;padding:0 28px}
  .menu a{font-family:var(--mono);font-size:20px;font-weight:600;letter-spacing:.14em;color:var(--grey);padding:18px 0;border-bottom:1px solid var(--hair)}
  .menu a:first-child{border-top:1px solid var(--hair)}
  .menu a.on{color:var(--ink)}
  .menu a.on::before{content:"";display:inline-block;width:9px;height:9px;background:var(--accent);margin-right:12px;vertical-align:1px}

  /* The desktop pane is height-constrained so its right column can scroll on
     its own. On mobile there is no second column and the page scrolls as one,
     so the flex constraint is released: basis back to auto, no shrinking, and
     the automatic minimum size restored.

     Grid also becomes block. The index bar below is position:sticky, and a
     sticky *grid item* is confined to its own grid area — a row sized exactly
     to its content, leaving it nowhere to travel, so it would never stick. As
     a plain block child its containing block is the whole section instead.

     --gutter is the single side inset for this screen: the index bar, the
     project text and the image strips all measure from it, so numbers, titles
     and photographs line up on one left edge. */
  .works{display:block;flex:0 0 auto;min-height:auto;height:auto;padding-top:0;--gutter:34px}

  /* Index bar: pinned below the fixed nav and scrolled sideways by main.js as
     each project comes into view. --nav-h is measured at runtime; the fallback
     matches the two-line brand at this size. Background is opaque so project
     content passes underneath rather than through it. */
  .works-list{
    position:sticky;top:0;z-index:20;
    display:flex;flex-direction:row;align-items:baseline;gap:26px;
    border-right:0;border-bottom:1px solid var(--hair);
    background:var(--ground);
    overflow-x:auto;overflow-y:hidden;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;-ms-overflow-style:none;
    scroll-behavior:smooth;
    padding:calc(var(--nav-h,78px) + 8px) var(--gutter) 12px;
  }
  .works-list::-webkit-scrollbar{display:none}
  /* number sits directly over its title — the desktop 10px row gap and the
     .no padding were what opened the space above each name */
  .works-list a{grid-template-columns:auto;white-space:nowrap;gap:2px;padding:0;line-height:1.35}
  .works-list a .no{padding-top:0}
  .works-list .lbl,.works-list .foot{display:none}

  .works-scroll{overflow:visible;height:auto;min-height:auto;padding:24px var(--gutter) 70px}
  /* clicking an index entry must land the project below the pinned bar, not
     behind it. --index-h is measured at runtime alongside --nav-h. */
  .proj{scroll-margin-top:calc(var(--index-h,132px) + 12px)}
  .proj:first-child{padding-top:8px}

  /* Project images become a horizontal scroll strip on mobile: uniform height,
     side by side, swipe to reveal the rest.

     The strip starts flush with the project text — no negative left margin, so
     the first image keeps the gutter — and bleeds off the right edge only, to
     show there is more to come. The trailing space is a flex ::after spacer
     rather than padding-right: padding at the far end of a scroll container is
     honoured inconsistently across mobile browsers, a zero-width flex item is
     not. */
  .proj-content{--strip-h:210px}
  .proj-content .wp-block-gallery,
  .proj-content .wp-block-gallery.is-layout-flex,
  .proj-content .wp-block-gallery .blocks-gallery-grid,
  .proj-content .gallery,
  .proj-content p:has(img ~ img),
  .proj-content p:has(picture ~ picture){
    display:flex;
    grid-template-columns:none;
    flex-wrap:nowrap;
    overflow-x:auto;
    scroll-snap-type:x proximity;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    margin-left:0;
    margin-right:calc(var(--gutter) * -1);
    padding-left:0;
    padding-right:0;
  }
  .proj-content .wp-block-gallery::after,
  .proj-content .gallery::after,
  .proj-content p:has(img ~ img)::after,
  .proj-content p:has(picture ~ picture)::after{
    content:"";
    flex:0 0 var(--gutter);
    clear:none;
    display:block;
  }
  .proj-content .wp-block-gallery::-webkit-scrollbar,
  .proj-content .gallery::-webkit-scrollbar,
  .proj-content p:has(img ~ img)::-webkit-scrollbar,
  .proj-content p:has(picture ~ picture)::-webkit-scrollbar{display:none}

  /* natural width at a shared height, so the next image peeks in and hints that
     the strip scrolls */
  .proj-content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#_),
  .proj-content .wp-block-gallery .wp-block-image:not(#_),
  .proj-content .wp-block-gallery .blocks-gallery-item:not(#_),
  .proj-content .gallery .gallery-item:not(#_),
  .proj-content p:has(img ~ img) > img,
  .proj-content p:has(picture ~ picture) > picture{
    flex:0 0 auto;
    width:auto;
    scroll-snap-align:start;
  }
  .proj-content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#_) img,
  .proj-content .wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#_) img,
  .proj-content .wp-block-gallery .wp-block-image:not(#_) img,
  .proj-content .wp-block-gallery .blocks-gallery-item:not(#_) img,
  .proj-content .gallery .gallery-item:not(#_) img,
  .proj-content p:has(img ~ img) > img,
  .proj-content p:has(picture ~ picture) img{
    height:var(--strip-h);
    width:auto;
    max-width:none;
    object-fit:cover;
  }

  /* ---------- two portraits: side by side, full width ----------
     main.js adds .is-pair to a gallery holding exactly two images that are
     both taller than they are wide. Nothing scrolls: the pair divides the
     screen between equal gutters, and each image keeps its own proportions.
     Detection has to happen in JS — CSS can count children but cannot ask an
     image which way up it is.

     These rules repeat the :not(#_) specificity trick used above, and sit
     after the strip rules so they win the ties.

     The even split below is only the JS-off fallback: main.js overrides
     grid-template-columns inline with the two images' ratios, so both land on
     the same height without being cropped. align-items:start keeps each figure
     at its natural height rather than stretching it to the row. */
  .proj-content .wp-block-gallery.is-pair,
  .proj-content .wp-block-gallery.is-pair.is-layout-flex,
  .proj-content .gallery.is-pair,
  .proj-content p.is-pair{
    display:grid;
    grid-template-columns:1fr 1fr;
    align-items:start;
    gap:14px;
    overflow:visible;
    margin-right:0;
    scroll-snap-type:none;
  }
  .proj-content .wp-block-gallery.is-pair::after,
  .proj-content .gallery.is-pair::after,
  .proj-content p.is-pair::after{display:none}

  .proj-content .is-pair.wp-block-gallery.has-nested-images figure.wp-block-image:not(#_),
  .proj-content .is-pair .wp-block-image:not(#_),
  .proj-content .is-pair .blocks-gallery-item:not(#_),
  .proj-content .is-pair .gallery-item:not(#_){
    width:auto;
    max-width:100%;
    min-width:0;
  }
  .proj-content .is-pair.wp-block-gallery.has-nested-images figure.wp-block-image:not(#_) img,
  .proj-content .is-pair.wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#_) img,
  .proj-content .is-pair .wp-block-image:not(#_) img,
  .proj-content .is-pair .blocks-gallery-item:not(#_) img,
  .proj-content .is-pair .gallery-item:not(#_) img,
  .proj-content p.is-pair > img,
  .proj-content p.is-pair picture img{
    width:100%;
    height:auto;
    max-width:100%;
    object-fit:contain;
  }
  .proj-content p.is-pair > img,
  .proj-content p.is-pair > picture{width:auto;min-width:0}

  .entry{grid-template-columns:1fr}

  .contact{padding:100px 20px 24px}
  .contact .big{font-size:clamp(26px,8vw,42px);line-height:1.18;max-width:none}
  .contact .corners{display:none}

  .scrollcue{display:block;position:absolute;left:50%;transform:translateX(-50%);bottom:22px;
             font-family:var(--mono);font-size:14px;font-weight:600;color:var(--grey);transition:opacity .3s}
  .scrollcue i{display:inline-block;font-style:normal;color:var(--accent);animation:bob 1.7s ease-in-out infinite}
  .scrollcue.gone{opacity:0}
}
