/* AGM site stylesheet: the frame only.
   What lives where:
   - Tokens (variables, colours), the type base, and container/section sizing: Bricks global variables, the AGM
     palette and the AGM theme style.
   - Everything an element carries (.agm-brand, .agm-nav, .agm-menubar, .agm-footer__grid, .agm-form, …):
     Bricks global classes, edited in the builder.
   - This file: what no element carries. The page base, the card printed around header and content, the
     header and footer landmarks, states set on <body> or on the landmarks by PHP and site.js, the Home opener
     (printed by inc/home.php), the case-page cover (inc/case.php) and the scroll-reveal and blur-in base.
   Bricks' own CSS sits in cascade layers, so every rule here wins over it without !important. */

/* ---------- Base ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html,body{overflow-x:clip} /* the big name runs past the right edge on purpose; it must never give the page a sideways scroll */
body{--page-tone:var(--footer-bg);transition:background-color .7s cubic-bezier(.2,.7,.2,1);margin:0;background:var(--page-tone);-webkit-font-smoothing:antialiased}
/* the footer takes the page tone too, so the frame around the card runs seamlessly into the footer */
.has-tone{--footer-bg:var(--page-tone)}
/* home: the space behind the video keeps the showreel's full tone; the margins below it and the footer take a lighter tint of the same colour */
body.is-home.has-tone{--footer-bg:color-mix(in srgb,var(--page-tone) 55%,#fbfbfb);background:var(--footer-bg)}
/* home: hovering the desk photo turns the frame and the footer a mid gray; the text stays dark, the small gray words a step darker
   so they still read (user, 2026-10-18: first #333 with light text, then "a little bit lighter gray", not a dark mode) */
body.is-home.is-tone-dark,body.is-home.has-tone.is-tone-dark{--footer-bg:#a7a7a7;background:var(--footer-bg)}
body.is-tone-dark .agm-footer :is(dt,.agm-top__word,.agm-top__mark,.agm-footer__privacy,.agm-footer__credit,.agm-footer__credit *){color:#474747;transition:color .7s cubic-bezier(.2,.7,.2,1)}
/* overlay-style scrollbar: transparent track over the frame colour, translucent thumb */
html{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.28) transparent}
::-webkit-scrollbar{width:10px;background:transparent}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(0,0,0,.28);border-radius:99px;border:2px solid transparent;background-clip:padding-box}
img,video{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4{margin:0}
p{margin:0}
ul{list-style:none;margin:0;padding:0}

/* ---------- Header landmark ---------- */
/* .agm-header is the header template's own <header id="brx-header"> (class added in inc/site-frame.php).
   Transparent, no box. It lives at the top of the card on every page, menu text 24px from the card edge, and
   scrolls away with the page like an ordinary menu; the bottom padding is the space above the intro. */
.agm-header{position:relative;z-index:60;height:auto;display:flex;align-items:flex-start;padding:2.4rem 0 9.6rem;box-sizing:border-box;background:transparent}
.agm-page.has-cover .agm-header{position:absolute;top:0;left:0;right:0} /* over a cover image the menu floats on the picture */
/* states set by site.js on the landmark, and by PHP on <body> */
.agm-header.is-away .agm-brand,.agm-header.is-away .agm-nav{pointer-events:none}
.agm-header.on-dark .agm-brand,.agm-header.on-dark .agm-nav a{color:rgba(244,244,242,.75)} /* over dark content */
.agm-header.on-dark .agm-brand,.agm-header.on-dark .agm-nav a:hover,.agm-header.on-dark .agm-nav a[aria-current]{color:#f4f4f2}
body.is-home .agm-nav a{color:var(--agm-black)} /* home: nothing is selected, so all four are black (body. lifts it over the agm-nav class) */
body.is-home .agm-nav a:hover{color:var(--agm-grey-700)} /* and hover goes grey */
.admin-bar .agm-menubar{top:var(--wp-admin--admin-bar--height,0px)} /* signed in: the menu strip sits below the WordPress toolbar */
@media (prefers-reduced-motion:reduce){.agm-header{animation:none}}

/* ---------- The card ---------- */
/* .agm-page is a wrapper printed around the header template and <main> (inc/site-frame.php). */
.agm-page{position:relative;z-index:1;background:var(--agm-off-white);margin:0 var(--m,var(--frame));border-radius:var(--r,0px) var(--r,0px) var(--rb,2.8rem) var(--rb,2.8rem);overflow:clip} /* inner pages: the card starts flush and full width at the top of the page; as you scroll its side margins (--m) and top corners (--r) draw in, the same curl as the home card (site.js). The bottom rounds off into the footer. */
/* inner pages: the card starts flush and full width. A scroll-driven animation (runs in step with
   the scroll on the compositor, so no lag) drops it by one frame while its side margins draw in
   and the top corners round, over the first --curl-run of scroll; then it scrolls away. The extra
   bottom margin pays for the drop so the footer reveal is unchanged. Without support the card is
   simply framed from the start. */
@supports (animation-timeline: scroll()){
  body:not(.has-chin) .agm-page{margin:0 0 calc(var(--curl-run) + var(--frame));animation:agmCurlFrame linear both,agmCurlMove linear both;animation-timeline:scroll(root),scroll(root);animation-range:0 var(--curl-run),0 var(--curl-run);will-change:transform}
  /* two animations on purpose: the movement is transform-only so it runs on the compositor, exactly in step with the scroll; the margins and corners (layout) run separately */
  @keyframes agmCurlFrame{from{margin-left:0;margin-right:0;border-top-left-radius:0;border-top-right-radius:0}to{margin-left:var(--frame);margin-right:var(--frame);border-top-left-radius:2.8rem;border-top-right-radius:2.8rem}}
  @keyframes agmCurlMove{from{transform:translateY(0)}to{transform:translateY(calc(var(--curl-run) + var(--frame)))}}
}

/* ---------- Footer landmark ---------- */
/* .agm-footer is the footer template's own <footer id="brx-footer"> (class added in inc/site-frame.php). */
.agm-footer{position:sticky;bottom:0;z-index:0;visibility:hidden}
.agm-footer.is-near{visibility:visible}
.agm-footer{transition:background-color .7s cubic-bezier(.2,.7,.2,1);background:var(--footer-bg);color:var(--footer-fg);padding:calc(var(--space-xl) + var(--space-m) + 2.8rem) 0 1.6rem;margin-top:-2.8rem;overflow:hidden}
.agm-footer>.brxe-container{position:relative;z-index:1}
/* contact links as on About: the text colour, grey under the pointer. :where() keeps this weaker than the
   global classes, so Back to top and Privacy policy keep their own hover colours */
:where(.agm-footer) a{transition:color .2s}
:where(.agm-footer) a:hover{color:var(--agm-grey-700)}

/* ---------- Home opener ---------- */
/* Printed by inc/home.php inside the card, in front of the header template. Full-width showreel; the page
   rises over it. The script (site.js 1b) scrubs it with the scroll: the reel lags behind (35% of the scroll)
   while the card's side margins (--m) and top corners (--r) draw in. */
.agm-opener-wrap{position:relative;height:100svh;min-height:48rem;overflow:clip;z-index:0;background:var(--agm-black)}
.agm-opener{position:relative;height:100%;overflow:hidden;background:var(--page-tone);transition:background-color .7s cubic-bezier(.2,.7,.2,1);color:var(--agm-off-white);transform-origin:50% 100%;will-change:transform}
/* the video fades into the page tone at its bottom edge, so there is no seam */
.agm-opener__media{position:absolute;inset:0;-webkit-mask-image:linear-gradient(to bottom,#000 66%,transparent 100%);mask-image:linear-gradient(to bottom,#000 66%,transparent 100%)}
.agm-opener__media video,.agm-opener__ph{width:100%;height:100%;object-fit:cover;display:block}
.agm-opener__ph{background:var(--page-tone);transition:background-color .7s cubic-bezier(.2,.7,.2,1)}
/* 16:9 embed scaled to cover the viewport, centred */
.agm-opener__video{position:absolute;top:50%;left:50%;width:max(100%, 177.78vh);height:max(100%, 56.25vw);max-width:none;transform:translate(-50%,-50%);pointer-events:none;border:0}
/* self-hosted reel: covers the opener like the embed, centred */
.agm-opener__media video.agm-opener__file{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 50%;pointer-events:none}
/* no overlay on the video: it is shown as shot */
.agm-opener__shade{position:absolute;inset:0;background:none;pointer-events:none}
.agm-opener__shade::after{content:"";position:absolute;inset:0;background:#000;opacity:var(--dim,0)}
/* the big name (hidden in this version) and its knockout band in the card's top edge; metrics set by the script */
.agm-name{position:absolute;left:var(--gutter);right:0;margin:0;font-family:var(--font-body);font-weight:500;text-transform:uppercase;letter-spacing:-.05em;line-height:1;white-space:nowrap;font-size:10vw;pointer-events:none;z-index:2}
.agm-name--light{display:none;bottom:0;left:0;padding-left:var(--frame);color:#fff}
.agm-name__track{display:inline-block;will-change:transform}
.agm-knockout{position:absolute;top:60svh;z-index:2;pointer-events:none;overflow:hidden;left:var(--m);width:calc(100% - 2 * var(--m));height:var(--band);border-radius:var(--r) var(--r) 0 0} /* at the card's top edge (the reel's height) */
.agm-knockout{min-width:0;min-height:0} /* Bricks gives an svg without a height attribute min-height:1em, which showed as a white bar on the card's top edge */
.agm-knockout__page{fill:var(--agm-off-white)}
.agm-knockout__text{font-family:var(--font-body);letter-spacing:-.05em}
.agm-after-opener{position:relative;z-index:1;background:var(--agm-off-white)}
/* home: the video is full-bleed; the content card carries the frame. Its side margins (--m) and top corner
   radius (--r) grow with the scroll, from flat and full-width to the framed card. */
.has-chin .agm-page{margin:0;border-radius:0;overflow:visible;background:transparent;padding-top:0;--m:0px;--r:0px;--band:40svh}
.has-chin .agm-opener-wrap{--reel:60svh;height:var(--reel);min-height:40rem;overflow:visible;background:var(--page-tone);transition:background-color .7s cubic-bezier(.2,.7,.2,1);z-index:auto} /* no stacking context, so the menu can sit above the card's top band */
.has-chin .agm-after-opener{z-index:auto;margin:0 var(--m);border-radius:var(--r) var(--r) var(--rb,2.8rem) var(--rb,2.8rem);background:linear-gradient(to bottom,transparent calc(var(--band) - 2px),rgba(251,251,251,var(--ca,1)) calc(var(--band) - 2px));-webkit-backdrop-filter:blur(var(--cb,0px));backdrop-filter:blur(var(--cb,0px))} /* the chin is slightly see-through and frosted at rest (--ca, --cb from site.js), solid and clear once it has become the card */
.has-chin .agm-after-opener .brxe-section{position:relative;z-index:3}
/* the reel is taller than its slot, so it runs on behind the card's top band */
.has-chin .agm-opener{overflow:visible}
/* the cover film's sink (0 -> 35% over the reel's height) follows the scroll on the compositor (user 2026-10-15: the film
   jittered while scrolling; site.js 1b's eased JS sink made it jump with each scroll step and slide back between steps).
   Same resting positions as the JS. ?agmsink=js brings the old JS sink back for comparison (html.agm-sink-js). */
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    html:not(.agm-sink-js) .has-chin .agm-opener{animation:agmOpenerSink linear both;animation-timeline:scroll(root);animation-range:0 max(var(--reel),var(--reel-min,40rem))}
  }
}
@keyframes agmOpenerSink{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,35%,0)}}
.has-chin .agm-opener__media{height:100svh;inset:auto 0 auto 0;top:0;-webkit-mask-image:linear-gradient(to bottom,#000 90%,transparent 100%);mask-image:linear-gradient(to bottom,#000 90%,transparent 100%)}
/* the video keeps its full width: a 16:9 box anchored at the top, only ever as tall as the reel slot needs
   (cover sizing against the whole viewport cut 96px off each side on a 1440x900 screen) */
.has-chin .agm-opener__media video.agm-opener__file{height:max(var(--reel,60svh),56.25vw);inset:0 0 auto 0}
/* home menu: in flow at the top of the card (the home card is also .has-cover, which floats the menu on
   inner cover pages); it rides up with the card. Load: the menu line fades down into place. */
.has-chin .agm-page .agm-header{position:relative;top:auto;height:auto;margin-bottom:0;padding:2.4rem 0 0}
.has-chin .agm-header .agm-header__row{justify-content:space-between;animation:agmMenuDown .7s cubic-bezier(.2,.7,.2,1) .25s both}
@keyframes agmMenuDown{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.agm-opener{will-change:auto}.has-chin .agm-header .agm-header__row{animation:none}}

/* ---------- Case pages ---------- */
/* Printed by inc/case.php on a single project: the cover, built like Home's opener (the chin mechanics above),
   with the chin lower down, 70% of the screen, so the cover gets more room. */
.is-case .agm-opener-wrap{--reel:50svh;--film:70svh;--reel-min:30rem;min-height:var(--reel-min)} /* the home's 40rem floor kept the card from rising on short windows */
/* user 2026-10-15: the card rises higher (50% of the screen, was 70%) while the film keeps its 70% box, so the film's lower
   part runs on behind the frosted header and lead card; where there is a cover film the still poster is hidden (it filled
   the whole window height and showed through the card as a second, frozen picture) */
.is-case .agm-opener__media video.agm-opener__file{height:max(var(--film),56.25vw);-webkit-mask-image:linear-gradient(to bottom,#000 max(var(--reel),var(--reel-min)),transparent);mask-image:linear-gradient(to bottom,#000 max(var(--reel),var(--reel-min)),transparent)} /* fades out behind the card, so its bottom edge never shows as a band */
.agm-opener__media:has(video.agm-opener__file) .agm-opener__poster{display:none}
/* Home gets the same cover treatment (user 2026-10-15, "site-wide"): card at 50% of the screen (was 60%), the film keeps its
   60% box and fades out behind the frosted card; Home has no page-tone layer, so its chin alone carries the frost: 65% white at
   rest (was 84%), about the project pages' total of tone 50% over white 30% */
.is-home .agm-opener-wrap{--reel:50svh;--film:60svh;--reel-min:30rem;min-height:var(--reel-min)}
.is-home .agm-opener__media video.agm-opener__file{height:max(var(--film),56.25vw);-webkit-mask-image:linear-gradient(to bottom,#000 max(var(--reel),var(--reel-min)),transparent);mask-image:linear-gradient(to bottom,#000 max(var(--reel),var(--reel-min)),transparent)}
.is-home .agm-after-opener{background:linear-gradient(to bottom,transparent calc(var(--band) - 2px),rgba(251,251,251,calc(.65 + .35 * var(--cx,1))) calc(var(--band) - 2px))}
/* the chin is only half opaque at rest, so the cover shows through the tone (blurred by the frost); it turns
   solid as the card rises (--cx from site.js 1b) */
.is-case .agm-after-opener{background:linear-gradient(to bottom,transparent calc(var(--band) - 2px),rgba(251,251,251,calc(.3 + .7 * var(--cx,1))) calc(var(--band) - 2px))}
/* the cover picture (the featured image), or its placeholder block until the photos exist */
.agm-opener__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;object-position:var(--focus,50% 50%)}
.agm-opener__media>.ph{background:#e2e0db}
.agm-opener__media>.ph--dark{background:#232323}
/* the project's introduction (menu row, facts, title, lead, index) sits on the page tone, translucent so the
   chin's frost still works, taking the card's top corners as they draw in. The prototype wraps the menu and the
   intro in one block; here the header carries the top of it and the intro section (agm-case-hero) the rest. */
/* header and lead card are one material: the page tone at --frost-tone (user 2026-10-15: 50%, was 60%, so more of the film shows
   through; the chin under them went from 45% to 30% white at rest). body.is-case lifts the lead card's rule over its Bricks class. */
body.is-case{--frost-tone:50%}
body.is-case .agm-header{background:color-mix(in srgb,var(--page-tone) var(--frost-tone),transparent);border-radius:var(--r,0px) var(--r,0px) 0 0}
body.is-case .agm-case-hero{background:color-mix(in srgb,var(--page-tone) var(--frost-tone),transparent)}

/* ---------- Motion ---------- */
/* Scroll reveal (site.js 2): elements with the class "reveal" wait below their place and arrive when they
   enter the view (.is-in). Frontend only, so the builder canvas shows everything at rest. What a single
   element adds to its own arrival (the project cards' picture, the Home portrait) is in its global class. */
.bricks-is-frontend .reveal{opacity:0;transform:translateY(14px);transition:opacity .7s ease var(--rd,0s),transform .7s cubic-bezier(.2,.7,.2,1) var(--rd,0s)}
.bricks-is-frontend .reveal.is-in{opacity:1;transform:none}
.reveal[data-delay="1"]{--rd:.08s}.reveal[data-delay="2"]{--rd:.16s}.reveal[data-delay="3"]{--rd:.24s}
/* a headline that comes into focus as it enters the view (the class "blur-in"); frontend only, like the reveal */
.bricks-is-frontend .blur-in{filter:blur(0);opacity:1}
@supports (animation-timeline: view()){
  .bricks-is-frontend .blur-in{animation:blurIn linear both;animation-timeline:view();animation-range:entry 0% entry 60%}
  @keyframes blurIn{from{filter:blur(10px);opacity:0}to{filter:blur(0);opacity:1}}
}
@media (prefers-reduced-motion:reduce){.bricks-is-frontend .reveal{opacity:1;transform:none;transition:none}.bricks-is-frontend .blur-in{animation:none}}

/* ---------- Silent loops ---------- */
/* A GIF printed as <video class="agm-loop"> (inc/journal.php) takes the picture's place and rules: it fills its
   frame like .agm-post__media img, and on a phone a set's picture keeps its own height */
.agm-post__media video.agm-loop{display:block;width:100%;height:100%;max-width:100%;object-fit:cover}
@media (max-width:767px){.agm-post__set .agm-post__media video.agm-loop{height:auto}}

/* ---------- Page transition: the reveal sweep (user's pick, 2026-10-15, after a fade, Extract Studio's wipe, a wipe down
   and a band sweep; EXTRACT-STUDY-2026-10-15.md §3) ----------
   One continuous sweep from top to bottom, nothing ever covering the page: the browser keeps a picture of the old page on
   top and cuts it away from the top edge down (.9s), so the new page shows above the moving edge and the old one below
   it. Cross-document View Transitions, CSS only (Chrome/Edge 126+, Safari 18.2+; other browsers load pages plainly).
   Off under Reduce Motion. */
@media (prefers-reduced-motion:no-preference){@view-transition{navigation:auto}}
::view-transition-group(root){animation:none}
::view-transition-new(root){z-index:1;animation:none;mix-blend-mode:normal}
::view-transition-old(root){z-index:2;animation:agmRevealOld .9s cubic-bezier(.65,0,.35,1) both;mix-blend-mode:normal} /* the default blend adds the two pictures into white */
@keyframes agmRevealOld{from{clip-path:inset(0 0 0 0)}to{clip-path:inset(100% 0 0 0)}}

/* Home About row: Visit about removed (user, 2026-10-29: "remove the 'Visit about' element under the lists, so no empty row is left"), so its
   fourth row is gone and the lists' bottom margin lines the table legs up with the last list line again. Phones: the photo goes under the
   intro and the lists (row 3). */
@media (max-width:767px){
  .agm-about-row--3 .agm-hero__portrait.agm-hero__portrait.agm-hero__portrait{grid-row:3}
}

/* Journal page: no captions in the feed; they stay on each post's own page (user, 2026-10-18) */
body.page-id-50 .agm-feed :is(.agm-slides__caption, figcaption.agm-caption, figcaption.agm-video__caption) { display: none !important; }

/* Projects page: Load more stands about a row gap below the last cards (user, 2026-10-18: "add more space above load more") */
.agm-grid ~ .agm-load { margin-top: clamp(8rem, 9.5vw, 14rem); }
