/* ==========================================================================
   Fhusster - studio site stylesheet (light theme)
   Palette: Midnight Navy #082B5C, Leather Black #121212 (text),
            Neon Magenta #FF2B73 (accent), Soft Bone #F2EFE8 (surface tint),
            Heavy Bag only: Olive #6E7450, Distressed Tan #B99C7A
   ========================================================================== */

:root{
  --bg:#FFFFFF;
  --ink:#121212;
  --ink-dim:rgba(18,18,18,.66);
  --navy:#082B5C;
  --bone:#F2EFE8;               /* used by ornament pieces on navy/olive */
  --surface:#F2EFE8;            /* Soft Bone card surface */
  --magenta:#FF2B73;
  --olive:#6E7450;              /* Heavy Bag only */
  --tan:#B99C7A;                /* Heavy Bag only */
  --line:rgba(18,18,18,.18);    /* default 2px border color */
  --radius:8px;
  --font-head:"Chakra Petch","Segoe UI",Arial,sans-serif;
  --font-body:"Inter","Segoe UI",Arial,sans-serif;
  --header-h:4.5rem;
  /* centered content column: 85% of the viewport, capped for large screens */
  --content-w:min(85%, 1320px);
}

*{margin:0;padding:0;box-sizing:border-box}
/* font-size 94% zooms the whole rem-based layout out slightly */
html{font-size:94%;scroll-behavior:smooth;scrollbar-gutter:stable}
body{
  background:var(--bg);
  color:var(--ink);
  font:400 1rem/1.65 var(--font-body);
  -webkit-font-smoothing:antialiased;
  overflow-x:clip; /* ribbon tails may reach past the column on small screens */
}
img{max-width:100%;display:block}
a{color:var(--magenta);text-decoration:none;transition:color .15s}
a:hover{text-decoration:underline}
:focus-visible{outline:2px solid var(--magenta);outline-offset:3px;border-radius:2px}

h1,h2,h3,h4{
  font-family:var(--font-head);
  text-transform:uppercase;
  letter-spacing:.06em;
  line-height:1.15;
  font-weight:600;
}
h1{font-size:clamp(2.1rem,5.5vw,3.6rem)}
h2{font-size:clamp(1.4rem,3vw,1.9rem)}
h3{font-size:1.1rem}

.wrap{width:var(--content-w);margin:0 auto}
/* background stays on body (same white) so the fixed side rails behind .site
   remain visible in the page margins */
.site{position:relative;z-index:200;min-height:100vh;display:flex;flex-direction:column;padding-top:var(--header-h)}
/* padding-top lives on .site (not body) so the fixed header, whose containing
   block becomes .site while .site is transformed during the intro slide, sits
   in exactly its final position throughout the animation. */
main{flex:1}

/* The corner swarm (assets/js/pixel-background.js). Its layer sits in <body>
   just AFTER .rails at the same z-index, so the side rails run BEHIND the
   art; .site (z 200) and its text stay above both. The canvas is sized to
   the device's own pixel grid, so the cubes' edges stay sharp. */
.pixel-field{position:absolute;left:0;right:0;top:0;z-index:0;overflow:hidden;pointer-events:none;user-select:none}
.pixel-background{display:block;position:absolute;top:0;right:0;max-width:none}
@media print{.pixel-field{display:none}}
@media (forced-colors:active){.pixel-field{display:none}}

.skip-link{
  position:absolute;left:-9999px;top:0;z-index:400;
  background:var(--magenta);color:#fff;font-family:var(--font-head);
  text-transform:uppercase;letter-spacing:.1em;padding:.6rem 1rem;border-radius:0 0 var(--radius) 0;
}
.skip-link:focus{left:0;text-decoration:none}

/* ==========================================================================
   Shared `extend` keyframe, ported verbatim from fhusster-intro.html.
   Used by the intro letters and the header logo hover. --d is the per-letter
   stagger delay; --sw the reference width the slide distance scales from.
   ========================================================================== */
@keyframes extend{
  0%   {opacity:0; transform:translateX(calc(-0.030 * var(--sw)));}
  40%  {opacity:1;}
  100% {opacity:1; transform:translateX(0);}
}

/* ==========================================================================
   Header + docked logo
   ========================================================================== */
.site-header{
  position:fixed;top:0;left:0;right:0;z-index:300;
  background:var(--bg);
  border-bottom:2px solid var(--line);
  height:var(--header-h);
}
.header-inner{
  width:var(--content-w);margin:0 auto;height:100%;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
}

/* The logo is a miniature of the intro stage (1672x941): the emblem sits in
   its docked position and the letter images keep their original stage
   coordinates, so the hover reveal lands exactly like the intro lockup.
   The art is navy on transparent, sitting directly on the page background. */
.logo{
  position:relative;display:block;flex:none;
  --sw:12.5rem;
  width:var(--sw);
  aspect-ratio:1672/941;
  margin-left:calc(-0.14713 * var(--sw)); /* pull the emblem flush to the page edge */
}
.logo-emblem{
  position:absolute;left:14.713%;top:30.818%;width:22.129%;height:39.107%;
}
.hletter{
  position:absolute;height:auto;opacity:0;pointer-events:none;
  transform:translateX(calc(-0.030 * var(--sw)));
  will-change:transform,opacity;
}
/* No-JS fallback only: site.js adds .js-reveal and drives the same reveal via
   the Web Animations API so it can rewind from the current point on mouse-out. */
.logo:not(.js-reveal):hover .hletter,
.logo:not(.js-reveal):focus .hletter,
.logo:not(.js-reveal):focus-visible .hletter{
  animation:extend .40s cubic-bezier(.25,.7,.2,1) var(--d) forwards;
}

.nav-toggle{
  display:none;background:none;border:2px solid var(--line);border-radius:var(--radius);
  width:2.75rem;height:2.5rem;cursor:pointer;padding:8px 9px;
  flex-direction:column;justify-content:space-between;
  transition:border-color .15s;
}
.nav-toggle:hover{border-color:var(--magenta)}
.nav-toggle-bar{display:block;height:2px;width:100%;background:var(--ink);transition:background .15s}
.nav-toggle:hover .nav-toggle-bar{background:var(--magenta)}

.site-nav ul{list-style:none;display:flex;gap:1.6rem}
.site-nav a{
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;
  font-size:.8rem;font-weight:600;color:var(--ink);
  padding:.4rem 0;border-bottom:2px solid transparent;
  transition:color .15s,border-color .15s;
}
.site-nav a:hover{color:var(--magenta);text-decoration:none}
.site-nav a[aria-current="page"]{color:var(--magenta);border-bottom-color:var(--magenta)}

@media (max-width:880px){
  :root{--header-h:3.75rem}
  .logo{--sw:10.625rem}
  .nav-toggle{display:flex}
  .site-nav{
    display:none;
    position:absolute;top:100%;left:0;right:0;
    background:var(--bg);border-bottom:2px solid var(--line);
  }
  .site-nav.open{display:block}
  .site-nav ul{flex-direction:column;gap:0;padding:.5rem 7.5% 1rem}
  .site-nav a{display:block;padding:.8rem 0;border-bottom:none}
  .site-nav a[aria-current="page"]{border-bottom:none}
}

/* ==========================================================================
   Buttons, badges, cards
   ========================================================================== */
/* Buttons are the corner swarm's blocks, squared off: a flat colour face
   with the same two receding faces the cubes have — a left flank and an
   underside, one and two shades deeper, lit from the upper right. Hovering
   presses the face down into its own extrusion while a sheen crosses it from
   the light's side. Every pair on the site is one magenta and one navy. */
/* Registered so the depth can be transitioned; inherited so the two face
   pseudo-elements, which are drawn from it, actually see it. */
@property --btn-dx{syntax:"<length>";inherits:true;initial-value:0px}
@property --btn-dy{syntax:"<length>";inherits:true;initial-value:0px}
@property --btn-sheen{syntax:"<color>";inherits:true;initial-value:transparent}
.btn{
  --face:var(--navy);
  --flank:#062045;            /* face x .75, as the cubes' side face */
  --under:#051935;            /* face x .58, as the cubes' underside */
  --btn-dx:5px;
  --btn-dy:6px;
  position:relative;
  /* Its own stacking context: without one, the faces (negative z-index) would
     paint under the background of any card the button sits on. */
  isolation:isolate;
  display:inline-block;
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.12em;
  font-weight:600;font-size:.85rem;
  /* +2px each side stands in for the 2px border these used to carry */
  padding:calc(.75rem + 2px) calc(1.5rem + 2px);
  border:0;border-radius:0;   /* sharp, like every block in the art */
  color:#fff;text-decoration:none;
  background-color:var(--face);
  /* the light catching the face, from the same corner it does in the art */
  --btn-sheen:transparent;
  background-image:radial-gradient(125% 150% at 100% 0,var(--btn-sheen),transparent 62%);
  cursor:pointer;
  transition:--btn-dx .14s ease-out,--btn-dy .14s ease-out,transform .14s ease-out,
             --btn-sheen .22s ease-out,text-shadow .18s;
}
/* The two receding faces, drawn outside the box as the cubes draw them.
   Negative z-index keeps them behind the face but above the page. */
.btn::before,.btn::after{content:"";position:absolute;z-index:-1;pointer-events:none}
.btn::before{                 /* left flank */
  left:calc(var(--btn-dx) * -1);top:0;
  width:var(--btn-dx);height:calc(100% + var(--btn-dy));
  background:var(--flank);
  clip-path:polygon(100% 0,100% calc(100% - var(--btn-dy)),0 100%,0 var(--btn-dy));
}
.btn::after{                  /* underside */
  left:calc(var(--btn-dx) * -1);top:100%;
  width:calc(100% + var(--btn-dx));height:var(--btn-dy);
  background:var(--under);
  clip-path:polygon(var(--btn-dx) 0,100% 0,calc(100% - var(--btn-dx)) 100%,0 100%);
}
/* Pressed: the face travels down the extrusion it was standing on, so the
   block's outer corner stays put and only the depth closes up. */
.btn:hover,.btn:focus-visible{
  color:#fff;text-decoration:none;
  --btn-dx:1.5px;--btn-dy:2px;
  transform:translate(-3.5px,4px);
  --btn-sheen:rgba(255,255,255,.4);
  text-shadow:0 0 14px rgba(255,255,255,.6),0 1px 0 rgba(0,0,0,.2);
}
.btn:active{--btn-dx:0px;--btn-dy:0px;transform:translate(-5px,6px);transition-duration:.06s}
/* A button on a dark surface keeps its face readable against it. */
.scan .btn,.card--navy .btn{--btn-sheen:rgba(255,255,255,.06)}
.btn:focus-visible{outline:2px solid var(--ink);outline-offset:5px}
.btn-primary{--face:var(--magenta);--flank:#BF2056;--under:#941943}
/* A button whose destination does not exist yet (assets/js/links.js): still
   in the layout, visibly not ready, and it does not press under the pointer. */
.btn--pending{opacity:.5;cursor:default}
.btn--pending:hover,.btn--pending:focus-visible{
  --btn-dx:5px;--btn-dy:6px;transform:none;--btn-sheen:transparent;text-shadow:none;
}
@media (prefers-reduced-motion:reduce){
  .btn{transition:--btn-sheen .22s ease-out,text-shadow .18s}
  .btn:hover,.btn:focus-visible,.btn:active{transform:none}
}

.badge{
  display:inline-block;
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;
  font-size:.68rem;font-weight:600;
  padding:.25em .8em;border:2px solid var(--line);border-radius:var(--radius);
  color:var(--ink-dim);
}
.badge-beta{color:var(--olive);border-color:var(--olive)} /* Heavy Bag status */

.card{
  border:2px solid var(--line);border-radius:var(--radius);
  background:var(--surface);
  transition:border-color .15s;
}
a.card-link{color:inherit;display:block}
a.card-link:hover{text-decoration:none}
.card:hover,.card:focus-within{border-color:var(--magenta)}

/* Art placeholder slots (SVG data-URI imgs until real art lands) */
.art{width:100%;height:auto;border-radius:calc(var(--radius) - 4px)}

/* ==========================================================================
   Sections
   ========================================================================== */
.section{padding:3.25rem 0}
.section-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin-bottom:1.75rem;flex-wrap:wrap}
.kicker{
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.22em;
  font-size:.75rem;font-weight:600;color:var(--magenta);display:block;margin-bottom:.9rem;
}
.lede{color:var(--ink-dim);font-size:1.1rem;max-width:44rem}

/* Donate band (Home) */
#donate{
  background:var(--surface);
  border-top:2px solid var(--line);
  border-bottom:2px solid var(--line);
  margin-top:2rem;
}

/* Hero */
.hero{padding:4.5rem 0 3.25rem} /* bottom edge is a .rule-dia divider */
/* Phones: less air above the kicker. The corner swarm rides the strip this
   leaves, so it is trimmed rather than closed. */
@media (max-width:640px){.hero{padding:2.4rem 0 2.6rem}}
.hero .lede{margin-top:1.2rem}
.hero-actions{margin-top:1.8rem;display:flex;gap:1rem;flex-wrap:wrap}

/* Featured game card (Home) */
.featured-card{display:grid;grid-template-columns:1fr 1fr;overflow:hidden}
/* The art IS the slot: no pad, no bed of card colour behind it, and the box
   is only as tall as the art itself, centred against the copy beside it.
   Both cards take the same column, and both pictures are the same shape, so
   the two slots come out identical. */
.featured-media{padding:0;background:transparent;align-self:center}
.featured-media .brk{padding:0}
.featured-media .art,.featured-media .reel,.featured-media video,.featured-media img{
  width:100%;height:auto;display:block;border-radius:0;
  /* contain, never cover: a clip that is a hair wider than the poster shows
     the card behind its edges rather than losing any of the frame. */
  object-fit:contain;background:transparent;
}
.featured-body{padding:1.8rem}
.featured-body h3{font-size:1.5rem;margin:.7rem 0 .2rem}
.featured-sub{color:var(--olive);font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;font-size:.78rem;font-weight:600}
.featured-body p{margin:1rem 0 1.4rem;color:var(--ink-dim)}
.featured-actions{display:flex;gap:.9rem;flex-wrap:wrap}
@media (max-width:760px){
  .featured-card{grid-template-columns:1fr}
  .featured-media{border-radius:calc(var(--radius) - 2px) calc(var(--radius) - 2px) 0 0}
}

/* Games grid */
.games-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,18rem),1fr));gap:1.5rem}
/* Every card in a row is one height: the grid stretches the <li>, and the
   link and the card inside it pass that height down instead of shrinking to
   their own copy, which is what left the taller subtitle sticking out. */
.games-grid > li{display:flex}
.games-grid > li > .card-link,
.games-grid > li > .card{display:flex;flex-direction:column;flex:1}
.game-card{display:flex;flex-direction:column;flex:1}
/* The art fills its slot edge to edge — no bed of card colour around it. */
.game-card-media{
  padding:0;overflow:hidden;
  aspect-ratio:1600/782;
  border-radius:calc(var(--radius) - 2px) calc(var(--radius) - 2px) 0 0;
}
.game-card-media .brk{padding:0;height:100%}
.game-card-media picture{display:block;height:100%}
.game-card-media .art{width:100%;height:100%;object-fit:cover;border-radius:0;display:block}
.game-card-media--hb{background:var(--olive)}
.game-card-body{padding:1.3rem 1.4rem 1.5rem;display:flex;flex-direction:column;gap:.55rem;flex:1}
.game-card-sub{font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;font-size:.75rem;font-weight:600;color:var(--ink-dim)}
.game-card--hb .game-card-sub{color:var(--olive)}
.game-card-meta{display:flex;gap:.6rem;align-items:center;margin-top:auto;padding-top:.7rem;flex-wrap:wrap}
.game-card-cta{font-family:var(--font-head);text-transform:uppercase;letter-spacing:.12em;font-size:.78rem;font-weight:600;color:var(--magenta);margin-left:auto}
.card-soon{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:.6rem;padding:2.5rem 1.5rem;min-height:17.5rem;
  border-style:dashed;background:transparent;
}
.card-soon:hover{border-color:var(--line)}
.card-soon h3{color:var(--ink-dim)}
.card-soon p{color:var(--ink-dim);font-size:.95rem}

/* Text pages */
.page-head{padding:3.25rem 0 2rem} /* bottom edge is a .rule-dia divider */
/* narrow prose columns sit centered; page-head headings above them keep the
   content column's left edge (user preference) */
.prose{max-width:46rem}
.prose p{margin-bottom:1.2rem}
.prose h2{margin:2.2rem 0 .8rem}
.prose ul{margin:0 0 1.2rem 1.2rem}
.prose li{margin-bottom:.4rem}

/* News */
.post{padding:1.8rem 2rem;margin-bottom:1.5rem}
.post time{
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.16em;
  font-size:.72rem;font-weight:600;color:var(--ink-dim);display:block;margin-bottom:.5rem;
}
.post h2{font-size:1.3rem;margin-bottom:.7rem}
.post p{color:var(--ink-dim)}
.post p + p{margin-top:.8rem}
.empty-state{color:var(--ink-dim);font-family:var(--font-head);text-transform:uppercase;letter-spacing:.16em;font-size:.8rem;margin-top:1rem}

/* Contact */
.contact-list{list-style:none;margin-top:1.5rem}
.contact-list li{margin-bottom:1rem;font-size:1.1rem}
.contact-label{
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.16em;
  font-size:.72rem;font-weight:600;color:var(--ink-dim);display:block;
}

/* Contact form */
.contact-form{margin-top:1.5rem;max-width:34rem}
.form-row{margin-bottom:1.2rem}
.form-row label{
  display:block;margin-bottom:.4rem;
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;
  font-size:.75rem;font-weight:600;color:var(--ink);
}
.form-row input,
.form-row textarea{
  width:100%;
  font:400 1rem/1.5 var(--font-body);color:var(--ink);
  background:var(--bg);
  border:2px solid var(--line);border-radius:var(--radius);
  padding:.7rem .9rem;
  transition:border-color .15s;
}
.form-row textarea{resize:vertical;min-height:9rem}
.form-row input:hover,
.form-row textarea:hover,
.form-row input:focus,
.form-row textarea:focus{border-color:var(--magenta);outline:none}
.form-honey{display:none}

/* ==========================================================================
   Heavy Bag game page theming (olive/tan lives here, not in studio chrome)
   ========================================================================== */
.hb-hero{padding:3.6rem 0 2.8rem} /* bottom edge is a .rule-dia divider */
.hb-hero .kicker{color:var(--olive)}
.hb-hero-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:2.5rem;align-items:center}
/* The art fills the frame: the olive mat is a hairline, not a mount. */
.hb-hero-media{padding:0;background:var(--olive);border:2px solid var(--tan);border-radius:var(--radius);overflow:hidden}
.hb-hero-media .brk{padding:0}
.hb-hero-media .art{border-radius:0;display:block}
.hb-hero-actions{margin-top:2rem;display:flex;gap:1rem;flex-wrap:wrap;align-items:center}
@media (max-width:820px){.hb-hero-grid{grid-template-columns:1fr}}
.shots-row{display:grid;grid-template-columns:repeat(3,1fr);gap:1.25rem}
.shot{padding:0;background:var(--olive);border:2px solid var(--line);border-radius:var(--radius);transition:border-color .15s;overflow:hidden}
.shot .brk{padding:0}
.shot .art{border-radius:0;display:block}
.shot:hover{border-color:var(--tan)}
@media (max-width:900px){.shots-row{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.shots-row{grid-template-columns:1fr}}
/* No forced ratio: the box follows the poster's own width and height, so the
   thumbnail is never cropped to fit a shape it is not. */
.hb-video{background:transparent}
.hb-modes{display:grid;grid-template-columns:repeat(2,1fr);gap:1.25rem}
.hb-mode{padding:1.4rem 1.5rem}
.hb-mode h3{color:var(--olive);margin-bottom:.5rem}
.hb-mode p{color:var(--ink-dim)}
@media (max-width:640px){.hb-modes{grid-template-columns:1fr}}
.hb-links{margin-top:.5rem;color:var(--ink-dim)}
.hb-links a{margin-right:1.2rem}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer{
  position:relative;flex:none;background:var(--bg);
  height:var(--header-h);border-top:1px solid var(--line);
  padding:0;margin-top:3.25rem;
}

/* Each complete cloud rests on the header baseline, beneath the navigation.
   Clip only this decorative layer so the mobile menu can still open below. */
.header-clouds{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:-1;
  /* Hidden until site.js has seen 30 idle minutes; scrolling fades them back
     into the white header (1.2s, matched by FADE_OUT_MS in site.js). */
  opacity:0;transition:opacity 1.2s ease-out}
.header-clouds.is-visible{opacity:1;transition:opacity 4s ease-in}
.header-cloud{position:absolute;bottom:0;width:clamp(150px,19vw,245px);height:100%}
.header-cloud:nth-child(1){left:-8%}
.header-cloud:nth-child(2){left:22%}
.header-cloud:nth-child(3){left:52%}
.header-cloud:nth-child(4){left:82%}
.header-clouds.js-clouds .header-cloud{left:0;will-change:transform}
.header-cloud img{position:absolute;bottom:0;width:100%;max-width:none;height:auto}
/* Compensate for each original PNG's transparent bottom margin. */
.header-cloud:nth-child(1) img{transform:translateY(16.85%)}
.header-cloud:nth-child(2) img{transform:translateY(26.86%)}
.header-cloud:nth-child(3) img{transform:translateY(19.8%)}
.header-cloud:nth-child(4) img{transform:translateY(21.82%)}
@media (max-width:600px){.header-cloud{width:clamp(74px,24vw,130px)}}
@media (prefers-reduced-motion:reduce){.header-clouds.js-clouds .header-cloud{will-change:auto}}
@media print,(forced-colors:active){.header-clouds{display:none}}
.footer-inner{
  width:var(--content-w);height:100%;margin:0 auto;
  display:flex;gap:1.5rem;align-items:center;justify-content:space-between;
}
.footer-brand{display:flex;align-items:center;gap:.8rem;min-width:0}
.footer-brand>a{flex:none}
.footer-emblem{width:2.6rem;height:auto}
.footer-copy{font-size:.72rem;line-height:1.45;color:var(--ink-dim)}
.footer-copy span{display:block}
.footer-nav ul{list-style:none;display:flex;gap:1.25rem;align-items:center}
.footer-nav a{
  font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;
  font-size:.72rem;font-weight:600;color:var(--ink);white-space:nowrap;
}
.footer-nav a:hover{color:var(--magenta);text-decoration:none}
.footer-toggle{display:none}
@media (max-width:1100px){
  .footer-toggle{display:flex;margin-left:auto}
  .footer-nav{
    display:none;position:absolute;bottom:100%;left:0;right:0;
    background:var(--bg);border-top:1px solid var(--line);border-bottom:1px solid var(--line);
    max-height:60vh;overflow-y:auto;
  }
  .footer-nav.open{display:block}
  .footer-nav ul{align-items:stretch;flex-direction:column;gap:0;padding:.5rem 7.5%}
  .footer-nav a{display:block;padding:.7rem 0}
}
@media (max-width:480px){
  .footer-inner{gap:.5rem}
  .footer-brand{gap:.5rem}
  .footer-emblem{width:2.2rem}
  .footer-copy{font-size:.68rem;line-height:1.4}
}

/* ==========================================================================
   Intro overlay - animation CSS ported verbatim from fhusster-intro.html,
   scoped under #intro. JS (assets/js/intro.js) drives the frame sequence.
   ========================================================================== */
#intro{display:none}
html.intro-pending{overflow:hidden}
html.intro-pending #intro{
  position:fixed;inset:0;z-index:100;background:#fff;
  display:flex;align-items:center;justify-content:center;
  --sw:min(88vw, 1100px);
  --sh:calc(var(--sw) * 941/1672);
}
/* the side rails ride the same slide as the site so they arrive together
   instead of popping in after the overlay is removed */
html.intro-pending .site,
html.intro-pending .pixel-field,
html.intro-pending .rails{transform:translateY(100vh)}
html.site-enter .site,
html.site-enter .pixel-field,
html.site-enter .rails{transform:translateY(0);transition:transform .7s ease-out}
/* during the slide the intro overlay (z 100) is still up; lift the rails
   above it (but below .site at 200) so they are visible while arriving */
html.site-enter .rails{z-index:150}
html.site-enter .pixel-field{z-index:151}

.intro-stage{position:relative;width:var(--sw);height:var(--sh);user-select:none}
#intro .emblem{
  position:absolute;
  left:14.713%; top:30.818%; width:22.129%; height:39.107%;
  transform:translate(calc(0.2422 * var(--sw)), calc(-0.0037 * var(--sh)));
  z-index:4;
  transform-origin:50% 50%;
}
#intro .emblem.docked{
  transform:none;
  transition:transform 0.3825s cubic-bezier(.35,.8,.25,1);
}
#intro .emblem .seq{
  position:absolute;
  left:-2.57%; top:-1.48%;
  width:103.97%; height:102.69%;
}
#intro .emblem .finalimg{
  position:absolute; inset:0; width:100%; height:100%;
  opacity:0; transition:opacity 0.18s linear;
}
#intro .emblem.docked .finalimg{opacity:1}
#intro .emblem.docked .seq{opacity:0; transition:opacity 0.18s linear}
#intro .letter{
  position:absolute; display:block; height:auto; pointer-events:none;
  opacity:0;
  transform:translateX(calc(-0.030 * var(--sw)));
  animation:extend 0.40s cubic-bezier(.25,.7,.2,1) var(--d) forwards;
  will-change:transform,opacity;
  z-index:1;
}
#intro .word{
  position:absolute; inset:0; z-index:1;
  transform-origin:50% 51.54%;
}

/* ==========================================================================
   Ornament kit, lifted from fhusster-ornaments_1.html and
   fhusster-ribbon-rails.html. Pieces in use: 01 diamond (as divider core),
   02 section divider, 03 HUD corner brackets, 08 scanline panel,
   12 waving ribbon (h2 banners; ornaments.js drives the ripple).
   ========================================================================== */

/* 01 · diamond mark */
.dia{width:14px;height:14px;transform:rotate(45deg);border:2px solid var(--magenta);display:inline-block}
.dia--sm{width:8px;height:8px}
.dia--fill{background:var(--magenta);border-color:var(--magenta)}

/* 02 · section divider: line, diamond, line. A beat between sections. */
.rule-dia{display:flex;align-items:center;gap:14px;width:100%}
.rule-dia::before,.rule-dia::after{content:"";height:2px;flex:1;background:var(--line)}
.rule-dia .dia{flex:none}
.hero .rule-dia{margin-top:2.6rem}
.page-head .rule-dia,.hb-hero .rule-dia{margin-top:1.8rem}

/* 03 · HUD corner brackets: corners only, lock inward on hover */
.brk{position:relative;padding:18px;display:block}
.brk::before,.brk::after,
.brk .b::before,.brk .b::after{
  content:"";position:absolute;width:18px;height:18px;
  border:0 solid var(--magenta);
  transition:inset .15s ease;
}
.brk::before{top:0;left:0;border-top-width:2px;border-left-width:2px}
.brk::after{top:0;right:0;border-top-width:2px;border-right-width:2px}
.brk .b::before{bottom:0;left:0;border-bottom-width:2px;border-left-width:2px}
.brk .b::after{bottom:0;right:0;border-bottom-width:2px;border-right-width:2px}
.brk:hover::before,a.card-link:hover .brk::before{top:6px;left:6px}
.brk:hover::after,a.card-link:hover .brk::after{top:6px;right:6px}
.brk:hover .b::before,a.card-link:hover .brk .b::before{bottom:6px;left:6px}
.brk:hover .b::after,a.card-link:hover .brk .b::after{bottom:6px;right:6px}
/* tan corners inside Heavy Bag's olive panels */
.brk--tan::before,.brk--tan::after,
.brk--tan .b::before,.brk--tan .b::after{border-color:var(--tan)}

/* 08 · scanline panel: CRT whisper, used as the footer sign-off strip */
.scan{position:relative;overflow:hidden;background:var(--navy);color:var(--bone)}
.scan::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(0deg,rgba(0,0,0,.28) 0 2px,transparent 2px 5px);
}
.footer-scan{display:flex;align-items:center;justify-content:center;padding:1rem 1.25rem;margin-bottom:2rem}
.footer-scan span{font-family:var(--font-head);text-transform:uppercase;letter-spacing:.14em;font-size:.78rem}

/* 12 · ribbon banner (fhusster-ribbon-rails.html). It hangs STILL and only
   ripples while the pointer is on it. Flat without JS or under reduced
   motion; ornaments.js slices the body into columns, which sit in register
   and read as one solid banner until the wave runs. */
.ribbon{
  --rib-body:var(--navy);
  --rib-tail:var(--magenta);
  --rib-fold:#8F1740;
  --rib-edge:rgba(242,239,232,.22);
  --rib-pad-y:12px;
  --rib-pad-x:34px;
  --rib-size:14px;
  --rib-drop:8px;            /* how far the tails sit below the body   */
  --rib-tail-w:44px;
  --rib-tail-out:32px;       /* how far the tails reach past the body  */
  --rib-slice:3px;           /* column width: the finer the grain, the  */
                             /* narrower any step the compositor leaves */
  --rib-amp:2px;             /* wave height, peak                      */
  --rib-period:1.2s;         /* one full ripple                        */
  --rib-lag:.0113s;          /* phase offset per column: period / lag  */
                             /* columns is the wavelength, here 320px  */
  position:relative;
  display:inline-block;
  vertical-align:middle;
}
.ribbon-body{
  position:relative;
  display:inline-flex;align-items:center;justify-content:center;
  white-space:nowrap;
  background:var(--rib-body);
  color:var(--bone);
  border-top:2px solid var(--rib-edge);
  border-bottom:2px solid var(--rib-edge);
  padding:var(--rib-pad-y) var(--rib-pad-x);
  font:700 var(--rib-size)/1 var(--font-head);
  text-transform:uppercase;letter-spacing:.14em;
}
.ribbon-tail{
  position:absolute;top:var(--rib-drop);height:100%;width:var(--rib-tail-w);
  background:var(--rib-tail);
  --i:0;
}
.ribbon-tail--l{left:calc(var(--rib-tail-out) * -1);clip-path:polygon(0 0,100% 0,100% 100%,0 100%,14px 50%)}
.ribbon-tail--r{right:calc(var(--rib-tail-out) * -1);clip-path:polygon(0 0,100% 0,calc(100% - 14px) 50%,100% 100%,0 100%)}
.ribbon-tail::after{
  content:"";position:absolute;bottom:0;width:11px;height:var(--rib-drop);
  background:var(--rib-fold);
}
.ribbon-tail--l::after{right:0;clip-path:polygon(100% 0,100% 100%,0 100%)}
.ribbon-tail--r::after{left:0;clip-path:polygon(0 0,0 100%,100% 100%)}
.ribbon-slice{
  position:absolute;top:-2px;bottom:-2px;left:0;right:0;
  background:var(--rib-body);
  border-top:2px solid var(--rib-edge);
  border-bottom:2px solid var(--rib-edge);
  /* Always drawn, sitting exactly on the solid body beneath them, so the
     ripple can start and finish as movement alone — nothing appears, and
     nothing changes size, when the pointer arrives. */
}
.ribbon-slice,.ribbon-tail{transition:transform .38s cubic-bezier(.22,.68,.2,1)}
.ribbon-label{position:relative;z-index:2}
/* Once the columns exist THEY draw the banner's edges — the body drops its
   own, which would otherwise double up with theirs and make the edge change
   brightness the moment the ripple starts. The body keeps its fill, so no
   seam between columns can ever show through. */
.ribbon.is-waving > .ribbon-body{border-color:transparent}
/* Pointer on the banner: the fill goes too, so the columns' moving edges are
   the banner's edges, and the ripple sets off along them. */
.ribbon.is-waving:hover > .ribbon-body,
.ribbon.is-waving:focus-within > .ribbon-body{background:transparent}
.ribbon.is-waving:hover .ribbon-slice,
.ribbon.is-waving:hover .ribbon-tail,
.ribbon.is-waving:focus-within .ribbon-slice,
.ribbon.is-waving:focus-within .ribbon-tail{
  animation:ribbon-wave var(--rib-period) linear infinite;
  /* POSITIVE delay: every column is at rest when the pointer arrives and
     starts from there, so the ripple sweeps in from the left instead of the
     whole banner jumping to mid-wave. Steady state is the same travelling
     wave either way. */
  animation-delay:calc(var(--i) * var(--rib-lag));
  will-change:transform;     /* keeps the sub-pixel offsets off the pixel grid */
}
@keyframes ribbon-wave{
  0%     {transform:translate3d(0,0,0)}
  6.25%  {transform:translate3d(0,calc(var(--rib-amp) * .383),0)}
  12.5%  {transform:translate3d(0,calc(var(--rib-amp) * .707),0)}
  18.75% {transform:translate3d(0,calc(var(--rib-amp) * .924),0)}
  25%    {transform:translate3d(0,calc(var(--rib-amp) * 1),0)}
  31.25% {transform:translate3d(0,calc(var(--rib-amp) * .924),0)}
  37.5%  {transform:translate3d(0,calc(var(--rib-amp) * .707),0)}
  43.75% {transform:translate3d(0,calc(var(--rib-amp) * .383),0)}
  50%    {transform:translate3d(0,0,0)}
  56.25% {transform:translate3d(0,calc(var(--rib-amp) * -.383),0)}
  62.5%  {transform:translate3d(0,calc(var(--rib-amp) * -.707),0)}
  68.75% {transform:translate3d(0,calc(var(--rib-amp) * -.924),0)}
  75%    {transform:translate3d(0,calc(var(--rib-amp) * -1),0)}
  81.25% {transform:translate3d(0,calc(var(--rib-amp) * -.924),0)}
  87.5%  {transform:translate3d(0,calc(var(--rib-amp) * -.707),0)}
  93.75% {transform:translate3d(0,calc(var(--rib-amp) * -.383),0)}
  100%   {transform:translate3d(0,0,0)}
}
.ribbon--sm{--rib-size:11px;--rib-pad-y:8px;--rib-pad-x:24px;--rib-tail-w:34px;--rib-tail-out:24px;--rib-drop:6px}
/* Heavy Bag variant: olive body, tan tails */
.ribbon--hb{--rib-body:var(--olive);--rib-tail:var(--tan);--rib-fold:#7A6249}
/* section-heading usage: h2 keeps the semantics, ribbon carries the look.
   Bottom margin clears the tails, which hang --rib-drop below the body. */
h2 .ribbon{--rib-size:1rem;--rib-pad-y:.85rem;--rib-pad-x:2.4rem;margin-bottom:1rem}

@media (prefers-reduced-motion:reduce){
  .ribbon.is-waving > .ribbon-body{background:var(--rib-body);border-color:var(--rib-edge)}
  .ribbon .ribbon-slice{display:none}
  .ribbon-slice,.ribbon-tail{transition:none}
  .ribbon.is-waving:hover .ribbon-tail,
  .ribbon.is-waving:focus-within .ribbon-tail{animation:none}
}

/* 13 · side rails: thick twin rails pinned to the viewport edges. One light
   circles the page: down the left rail, then up the right the moment it
   lands, then around again. Light-theme adaptation: the base rail is faded
   and the traveling light is the full-strength color (a brightness boost
   would wash out on white). Rails sit behind .site; opaque full-bleed
   elements (header, bands, scan strip) pass in front of them. */
.rails{
  position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  /* brightness ramp for the traveling light: 25 hard steps of 4%, symmetric.
     The most opaque pixel sits in the MIDDLE, sandwiched between pixels that
     step gradually lighter toward both ends. Same mask works for either
     travel direction. */
  --rail-ramp:linear-gradient(180deg,
    rgba(0,0,0,.08) 0 4%,   rgba(0,0,0,.16) 4% 8%,   rgba(0,0,0,.24) 8% 12%,
    rgba(0,0,0,.32) 12% 16%, rgba(0,0,0,.40) 16% 20%, rgba(0,0,0,.48) 20% 24%,
    rgba(0,0,0,.56) 24% 28%, rgba(0,0,0,.64) 28% 32%, rgba(0,0,0,.72) 32% 36%,
    rgba(0,0,0,.80) 36% 40%, rgba(0,0,0,.88) 40% 44%, rgba(0,0,0,.96) 44% 48%,
    #000 48% 52%,
    rgba(0,0,0,.96) 52% 56%, rgba(0,0,0,.88) 56% 60%, rgba(0,0,0,.80) 60% 64%,
    rgba(0,0,0,.72) 64% 68%, rgba(0,0,0,.64) 68% 72%, rgba(0,0,0,.56) 72% 76%,
    rgba(0,0,0,.48) 76% 80%, rgba(0,0,0,.40) 80% 84%, rgba(0,0,0,.32) 84% 88%,
    rgba(0,0,0,.24) 88% 92%, rgba(0,0,0,.16) 92% 96%, rgba(0,0,0,.08) 96% 100%);
}
.rail{
  --rail-a:var(--magenta);
  --rail-b:var(--navy);
  --rail-cycle:13s;          /* 2.5s down + 2.5s up + 8s rest between pairs    */
  --rail-len:100vh;          /* tail spans the whole viewport                  */
  /* One rail is two coloured bars with a gap: the three widths below are its
     whole geometry, so a narrow screen resizes the rail by changing them. */
  --rail-w:16px;
  --rail-bar:6px;
  --rail-gap:4px;
  --rail-inset:14px;
  position:absolute;top:0;bottom:0;width:var(--rail-w);
}
/* Both bars, used by the base line and by the travelling light. */
.rail{
  --rail-bars:linear-gradient(90deg,
    var(--rail-a) 0 var(--rail-bar),
    transparent var(--rail-bar) calc(var(--rail-bar) + var(--rail-gap)),
    var(--rail-b) calc(var(--rail-bar) + var(--rail-gap)) var(--rail-w));
}
/* base line on a pseudo so its 50% fade does NOT cap the light's opacity
   (element opacity would apply to the whole subtree, light included) */
.rail::before{
  content:"";position:absolute;inset:0;
  opacity:.5;
  background:var(--rail-bars);
}
.rail--l{left:var(--rail-inset)}
.rail--r{right:var(--rail-inset);--rail-a:var(--navy);--rail-b:var(--magenta)}   /* mirrored */
.rail-light{
  position:absolute;left:0;right:0;height:var(--rail-len);
  background:var(--rail-bars);
  filter:saturate(1.6);
  opacity:0;
}
/* stepped brightness ramp, most opaque in the middle */
.rail--l .rail-light{
  -webkit-mask-image:var(--rail-ramp);
          mask-image:var(--rail-ramp);
  animation:rail-down var(--rail-cycle) linear infinite;
}
.rail--r .rail-light{
  -webkit-mask-image:var(--rail-ramp);
          mask-image:var(--rail-ramp);
  animation:rail-up var(--rail-cycle) linear infinite;
  animation-delay:calc(var(--rail-cycle) * .1923);  /* takes over as the left lands */
}
/* each pass takes 19.23% of the 13s cycle (2.5s); the rest is the 8s pause
   after the pair completes */
@keyframes rail-down{
  0%      {transform:translateY(calc(var(--rail-len) * -1));opacity:1}
  19.23%  {transform:translateY(100vh);opacity:1}
  19.231%,100%{transform:translateY(100vh);opacity:0}
}
@keyframes rail-up{
  0%      {transform:translateY(100vh);opacity:1}
  19.23%  {transform:translateY(calc(var(--rail-len) * -1));opacity:1}
  19.231%,100%{transform:translateY(calc(var(--rail-len) * -1));opacity:0}
}
/* The rails used to be dropped below 640px. They stay now, narrowed — but
   by less than the page around them, so they still read as the same pair of
   rails rather than hairlines: 16px to 11px where the body text barely
   changes, and the inset comes in with them so the margin still clears. */
@media (max-width:640px){
  .rail{--rail-w:11px;--rail-bar:4px;--rail-gap:3px;--rail-inset:8px}
}
@media (max-width:380px){
  .rail{--rail-w:9px;--rail-bar:3.5px;--rail-gap:2px;--rail-inset:6px}
}
@media (prefers-reduced-motion:reduce){.rail-light{display:none}}

/* ==========================================================================
   Reduced motion
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *{transition-duration:.01ms !important;animation-duration:.01ms !important}
  .logo:hover .hletter,
  .logo:focus .hletter,
  .logo:focus-visible .hletter{animation:none;opacity:1;transform:none}
}

/* Heavy Bag: the live control diamond (assets/js/diamond.js). Drawn in
   ink on the page itself — no panel — small, between the two paragraphs. */
.hb-diamond-figure{margin:3.4rem auto 0;max-width:960px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.hb-diamond{min-width:760px;aspect-ratio:1800/760}
.hb-diamond svg{display:block;width:100%;height:auto}
.hb-diamond-actions{margin:1.2rem 0 3.4rem;text-align:center}
/* the section's copy sits in the same centred column The Game uses */
.hb-copy{margin-left:auto;margin-right:auto}

/* ==========================================================================
   Dad Reflex game page theming
   Heavy Bag wears olive/tan; Dad Reflex wears the studio's own navy and
   magenta. Every rule below is additive — nothing here overrides a
   Heavy Bag selector.
   ========================================================================== */

/* Dad Reflex-themed button, game pages/cards only */
/* Dad Reflex's own button is the navy of the pair, spelled out for the page. */
.btn-dr{--face:var(--navy);--flank:#062045;--under:#051935}

/* Shipped. The studio's action colour, so a live game reads as live. */
.badge-live{color:var(--magenta);border-color:var(--magenta)}

/* Grid card */
.game-card-media--dr{background:var(--navy)}
.game-card--dr .game-card-sub{color:var(--navy)}

/* Featured card (Home). The base rules hardcode olive, so these override
   for the Dad Reflex card only and leave Heavy Bag's untouched. */

.featured-card--dr .featured-sub{color:var(--navy)}

/* Detail page hero */
.dr-hero{padding:3.6rem 0 2.8rem} /* bottom edge is a .rule-dia divider */
.dr-hero .kicker{color:var(--magenta)}
.dr-hero .rule-dia{margin-top:1.8rem}
.dr-hero-grid{display:grid;grid-template-columns:.95fr 1.05fr;gap:2.5rem;align-items:center}
/* The art fills the frame, exactly as Heavy Bag's does: the navy mat is a
   hairline, not a mount. A thick inner border reads as a screenshot of a
   screenshot. */
.dr-hero-media{padding:0;background:var(--navy);border:2px solid var(--magenta);border-radius:var(--radius);overflow:hidden}
.dr-hero-media .brk{padding:0}
.dr-hero-media .reel,.dr-hero-media .art{border-radius:0;display:block;width:100%;height:auto}
.dr-hero-actions{margin-top:2rem;display:flex;gap:1rem;flex-wrap:wrap;align-items:center}
@media (max-width:820px){.dr-hero-grid{grid-template-columns:1fr}}
.dr-links{margin-top:.5rem;color:var(--ink-dim)}
.dr-links a{margin-right:1.2rem}

/* ==========================================================================
   Reels: autoplaying muted gameplay loops
   The site had no video before this. A reel is framed exactly like the
   art placeholders — HUD corner brackets over a padded panel — and the
   intrinsic ratio comes from the width/height attributes, as it does for
   every .art image.
   ========================================================================== */
.reel{
  display:block;width:100%;height:auto;
  border-radius:calc(var(--radius) - 4px);
}
/* The card reel sits in the same padded slot the key art would. */


/* Dad Reflex screenshots.
   The game is LANDSCAPE-only (the iOS target declares landscape left and
   right and nothing else), so the frames are landscape phone-shaped. A
   portrait frame would be three quarters empty mat. */
.dr-shots{
  display:grid;grid-auto-flow:column;grid-auto-columns:minmax(19rem,1fr);
  gap:1.25rem;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  padding-bottom:.9rem;  /* room for the scrollbar, so it never overlaps a frame */
}
.dr-shot{
  scroll-snap-align:start;
  padding:0;background:var(--navy);
  border:2px solid var(--line);border-radius:var(--radius);
  transition:border-color .15s;overflow:hidden;
}
.dr-shot .brk{padding:0}
.dr-shot .art{border-radius:0;display:block;width:100%;height:auto}
.dr-shot:hover{border-color:var(--magenta)}
/* Match the site's own scrollbar restraint: visible, thin, in palette. */
.dr-shots::-webkit-scrollbar{height:8px}
.dr-shots::-webkit-scrollbar-track{background:var(--surface);border-radius:4px}
.dr-shots::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}
.dr-shots::-webkit-scrollbar-thumb:hover{background:var(--magenta)}
@media (max-width:640px){.dr-shots{grid-auto-columns:minmax(16rem,1fr)}}

/* Studio headings keep their filled type, with a fine gradient outline. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
[id]{scroll-margin-top:calc(var(--header-h) + 1.5rem)}
.site-header{border-bottom-width:1px}
.site-nav a{letter-spacing:.1em}
.studio-headline span,.studio-page .page-head h1 span{
  background:linear-gradient(to bottom,var(--navy) 25%,var(--magenta) 80%);
  background-clip:text;-webkit-background-clip:text;
  -webkit-text-stroke:2px transparent;
  color:inherit;paint-order:stroke fill;
}
.studio-index{display:block;color:var(--navy);font:600 .72rem/1.5 var(--font-head);letter-spacing:.16em;text-transform:uppercase}
.text-link{color:var(--navy);font-size:.85rem;font-weight:600;text-underline-offset:5px}
.studio-home .section{padding:3rem 0}
.studio-home .featured-card{border-width:1px;background:#faf9f6;box-shadow:0 12px 36px rgba(8,43,92,.045)}
.studio-home .featured-body{align-self:center;padding:2rem 2.25rem}
.studio-home .featured-body h3{font-size:clamp(1.6rem,2.5vw,2.35rem);letter-spacing:.025em}
.studio-home .featured-body p{font-size:.95rem;line-height:1.8}
/* The home cards' own override used to stretch the slot to the copy's height
   and pad it; the slot hugs the art instead. */
.studio-home .featured-media{align-self:center;display:flex;align-items:center;padding:0}
/* The card is as tall as the picture and no taller: the slot takes a wider
   share of the row, and the copy beside it is set tight enough to fit that
   height, so no card colour is left showing above or below the art. */
.studio-home .featured-card{grid-template-columns:minmax(0,1.2fr) minmax(13rem,1fr)}
.studio-home .featured-body{padding:1.1rem 1.4rem;gap:0}
.studio-home .featured-title{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;margin-bottom:.15rem}
.studio-home .featured-title h3{font-size:1.32rem;margin:0}
.studio-home .featured-body .featured-sub{font-size:.7rem}
.studio-home .featured-body p{font-size:.93rem;line-height:1.5;margin:.5rem 0 .85rem}
.studio-home .featured-actions{margin-top:0}
.studio-home .featured-actions .btn{font-size:.76rem;padding:calc(.58rem + 2px) calc(1.1rem + 2px)}
/* Side by side only survives where the copy can fit the picture's height.
   Measured, that is about 1400px and up; below it the card stacks, which
   gives the art the full width and leaves no colour above or below it
   either. The copy goes back to a comfortable size there, capped so the
   lines do not run the whole width of a wide card. */
@media (max-width:1399px){
  .studio-home .featured-card,
  .studio-home .featured-card.is-expanded{grid-template-columns:minmax(0,1fr)}
  .studio-home .featured-body{padding:1.4rem 1.7rem 1.6rem}
  .studio-home .featured-title h3{font-size:1.45rem}
  .studio-home .featured-body .featured-sub{font-size:.74rem}
  .studio-home .featured-body p{font-size:.95rem;line-height:1.65;max-width:52rem}
  .studio-home .featured-actions .btn{font-size:.8rem;padding:calc(.65rem + 2px) calc(1.25rem + 2px)}
}
.studio-home .featured-media>.brk{width:100%;padding:0}
.studio-home .featured-media video{border-radius:3px}
.studio-principles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2.5rem;margin:2.5rem 0}
.studio-principles>div{border-top:1px solid var(--line);padding-top:1.25rem}
.studio-principles h3{margin:.7rem 0;font-size:1.15rem;letter-spacing:.025em;color:var(--navy)}
.studio-principles p{font-size:.95rem;color:var(--ink-dim);max-width:25rem}
.studio-home #donate{background:#f7f6f2;border-width:1px}
.studio-home #donate .btn{margin:0 .6rem .6rem 0}
.studio-page .page-head{padding-top:4.5rem}
.studio-page .page-head h1{letter-spacing:.025em;color:var(--navy)}
.studio-page .prose{font-size:1.05rem;line-height:1.85}
.studio-page .post{background:#faf9f6;border-width:1px;padding:2rem}
.studio-page .contact-form{background:#faf9f6;border:1px solid var(--line);padding:1.75rem;border-radius:var(--radius)}
.footer-copy{max-width:29rem}
.footer-nav a{letter-spacing:.08em}
.footer-scan{padding:.8rem 1.25rem}

/* Matching grid track functions at both ends allow continuous interpolation.
   The video keeps its intrinsic aspect ratio as the text column reflows. */
.featured-card,.hb-hero-grid,.dr-hero-grid{transition:grid-template-columns .65s cubic-bezier(.22,.68,.2,1),gap .65s}
.featured-card{grid-template-columns:minmax(0,1fr) minmax(15rem,1fr)}
.hb-hero-grid{grid-template-columns:minmax(15rem,1.1fr) minmax(0,.9fr)}
.dr-hero-grid{grid-template-columns:minmax(15rem,.95fr) minmax(0,1.05fr)}
.featured-card>* ,.hb-hero-grid>* ,.dr-hero-grid>*{min-width:0}
.featured-card.is-expanded{grid-template-columns:minmax(0,2.6fr) minmax(15rem,1fr)}
.featured-body{transition:padding .65s}
.featured-card.is-expanded .featured-body{padding:1.5rem}
.preview-description{display:grid;grid-template-rows:1fr;opacity:1;transition:grid-template-rows .65s cubic-bezier(.22,.68,.2,1),opacity .35s}
.preview-description>div{min-height:0;overflow:hidden}
.is-expanded .preview-description{grid-template-rows:0fr;opacity:0}
.featured-actions{transition:margin .65s,gap .65s}
.featured-card.is-expanded .featured-actions{margin-top:1.25rem;gap:.7rem}
.hb-hero-grid.is-expanded,.dr-hero-grid.is-expanded{grid-template-columns:minmax(15rem,.75fr) minmax(0,2.25fr);gap:2rem}
.hb-hero-grid h1,.dr-hero-grid h1{transition:font-size .65s}
.hb-hero-grid.is-expanded h1,.dr-hero-grid.is-expanded h1{font-size:clamp(2rem,3vw,3rem)}
.hb-hero-actions,.dr-hero-actions{transition:margin .65s}
.hb-hero-grid.is-expanded .hb-hero-actions,.dr-hero-grid.is-expanded .dr-hero-actions{margin-top:1.25rem}
.featured-media,.hb-hero-media,.dr-hero-media{transition:margin .65s cubic-bezier(.22,.68,.2,1)}
.expandable-media{isolation:isolate}
.expandable-media::before,.expandable-media::after,.expandable-media .b{pointer-events:none}
.media-expand{position:absolute;inset:0;z-index:1;width:100%;border:0;background:transparent;cursor:zoom-in;border-radius:inherit}
/* Home page reels wait to be asked. The badge is the block the rest of the
   site is built from: a flat navy face on its own extrusion, pressed on
   hover. It steps aside once the reel is running, and comes back on hover
   (or focus) as the pause control. */
.media-play{
  --face:var(--navy);
  /* The block the badge stands on is the pair's other colour: magenta, with
     the underside a shade deeper so the two planes still read as two. */
  --flank:var(--magenta);
  --under:#CC1F59;
  --btn-dx:5px;
  --btn-dy:6px;
  --badge-fade:.22s;
  position:absolute;left:50%;top:50%;z-index:2;
  isolation:isolate;            /* faces stay above the artwork, under the face */
  width:66px;height:66px;margin:-33px 0 0 -33px;
  border:0;border-radius:0;padding:0;cursor:pointer;
  opacity:.8;                   /* the artwork reads through it */
  background-color:var(--face);
  /* The same light the buttons catch, from the same corner it comes from
     in the art: parked transparent, faded in on hover. */
  --btn-sheen:transparent;
  background-image:radial-gradient(125% 150% at 100% 0,var(--btn-sheen),transparent 62%);
  display:flex;align-items:center;justify-content:center;
  transition:transform .14s ease-out,--btn-dx .14s ease-out,--btn-dy .14s ease-out,
             --btn-sheen .22s ease-out,opacity var(--badge-fade) ease-out;
}
/* The same two receding faces every other button has, joined corner to
   corner with the face instead of the offset copy a box-shadow gives. */
.media-play::before,.media-play::after{content:"";position:absolute;z-index:-1;pointer-events:none}
.media-play::before{              /* left flank */
  left:calc(var(--btn-dx) * -1);top:0;
  width:var(--btn-dx);height:calc(100% + var(--btn-dy));
  background:var(--flank);
  clip-path:polygon(100% 0,100% calc(100% - var(--btn-dy)),0 100%,0 var(--btn-dy));
}
.media-play::after{               /* underside */
  left:calc(var(--btn-dx) * -1);top:100%;
  width:calc(100% + var(--btn-dx));height:var(--btn-dy);
  background:var(--under);
  clip-path:polygon(var(--btn-dx) 0,100% 0,calc(100% - var(--btn-dx)) 100%,0 100%);
}
.media-play-icon{
  width:30px;height:30px;display:block;overflow:visible;
}
/* paint-order draws the stroke first and the fill over it, so the visible
   outline is the stroke's outer half — an even 1px, kept at 1px on any size
   by non-scaling-stroke. */
.media-play-icon path,.media-play-icon rect{
  fill:var(--magenta);stroke:#fff;stroke-width:2;
  stroke-linejoin:miter;stroke-miterlimit:8;
  paint-order:stroke fill;
  vector-effect:non-scaling-stroke;
}
.media-play-icon .icon-pause{display:none}
.media-play:hover,.media-play:focus-visible{
  --btn-dx:1.5px;--btn-dy:2px;transform:translate(-3.5px,4px);
  --btn-sheen:rgba(255,255,255,.4);
}
.media-play:active{--btn-dx:0px;--btn-dy:0px;transform:translate(-5px,6px);transition-duration:.06s}
/* White ring: the badge sits on artwork, and magenta would now land on the
   magenta base right beside it. */
.media-play:focus-visible{outline:3px solid #fff;outline-offset:5px}
/* Playing: the badge fades back and becomes two bars, on hand but out of the
   way. It follows the POINTER — leaving the frame takes it with you — and
   :focus-visible rather than :focus-within means a click does not pin it
   there until you click somewhere else. */
.expandable-media.is-playing .media-play{opacity:0;pointer-events:none;--badge-fade:.5s}
.expandable-media.is-playing:hover .media-play,
.expandable-media.is-playing:has(.media-play:focus-visible) .media-play{opacity:.8;pointer-events:auto;--badge-fade:.18s}
.expandable-media.is-playing .media-play-icon .icon-play{display:none}
.expandable-media.is-playing .media-play-icon .icon-pause{display:block}
@media (max-width:600px){
  .media-play{width:54px;height:54px;margin:-27px 0 0 -27px;--btn-dx:4px;--btn-dy:5px}
  .media-play-icon{width:24px;height:24px}
  .expandable-media.is-playing .media-play{opacity:.55;pointer-events:auto}
}
@media (prefers-reduced-motion:reduce){
  .media-play{transition:--btn-sheen .22s ease-out,opacity var(--badge-fade) ease-out}
  .media-play:hover,.media-play:focus-visible,.media-play:active{transform:none}
}
.media-expand[aria-expanded="true"]{cursor:zoom-out}
.media-expand:focus-visible{outline:3px solid var(--magenta);outline-offset:-5px}

@media (max-width:1000px){
  .studio-home .featured-body{padding:1.5rem}
}
@media (max-width:820px){
  .hb-hero-grid,.dr-hero-grid,.hb-hero-grid.is-expanded,.dr-hero-grid.is-expanded{grid-template-columns:minmax(0,1fr);gap:1.5rem}
  .hb-hero-grid.is-expanded .hb-hero-actions,.dr-hero-grid.is-expanded .dr-hero-actions{flex-direction:row;align-items:center}
  .hb-hero-grid.is-expanded .hb-hero-media,.dr-hero-grid.is-expanded .dr-hero-media{margin-inline:-5vw}
  .studio-principles{gap:1.4rem}
}
@media (max-width:760px){
  .featured-card,.featured-card.is-expanded{grid-template-columns:minmax(0,1fr);overflow:visible}
  .featured-card.is-expanded .featured-media{margin-inline:-5vw;border-radius:var(--radius)}
  .featured-card.is-expanded .featured-actions{flex-direction:row;align-items:center}
  .studio-home .featured-body{padding:1.4rem}
  .studio-principles{grid-template-columns:1fr;gap:1.25rem}
  .studio-home .section{padding:2rem 0}
  .studio-page .page-head{padding-top:2.5rem}
}
@media (max-width:480px){
  .studio-home .kicker{font-size:.65rem;letter-spacing:.14em}
  .studio-page .contact-form{padding:1rem}
  .footer-scan span{font-size:.68rem}
}
@media (max-width:640px){
  /* The rails run 8-19px in from each edge here, so the banner has to finish
     clear of them: the body text, its padding and the tails all come down
     together, and the tails reach 7px rather than 18 so they land inside. */
  h2 .ribbon{--rib-size:.82rem;--rib-pad-y:.62rem;--rib-pad-x:1.3rem;
             --rib-tail-w:24px;--rib-tail-out:7px;--rib-drop:5px;margin-bottom:.85rem}
}

/* ==========================================================================
   Screenshot lightbox (site.js)
   A click lifts the screenshot out of its frame and grows it to its real
   size in the middle of the screen while everything behind greys out; a
   click away or Esc plays the same move backwards. The flying image is a
   fixed-position copy moved with a transform only, so the page never
   reflows under it. The grey rides the same clock as the growth, quick
   enough to read as a fade.
   ========================================================================== */
.shot img.art,.dr-shot img.art{cursor:zoom-in}
.shot img.art:focus-visible,.dr-shot img.art:focus-visible{outline:3px solid var(--magenta);outline-offset:-3px}
.lightbox-shade{
  position:fixed;inset:0;z-index:1000;background:rgba(18,20,28,.8);
  opacity:0;transition:opacity .2s ease-out;cursor:zoom-out;
}
.lightbox-shade.is-on{opacity:1}
.lightbox-img{
  position:fixed;left:0;top:0;z-index:1001;margin:0;max-width:none;
  transform-origin:0 0;transition:transform .24s cubic-bezier(.2,.75,.25,1);
  will-change:transform;cursor:zoom-out;border-radius:8px;
  box-shadow:0 24px 70px rgba(0,0,0,.55);
}
.is-lightbox-source{visibility:hidden}
@media (prefers-reduced-motion:reduce){
  .lightbox-shade,.lightbox-img{transition:none}
}
