/*
 * AppAlbania
 *
 * One stylesheet. The tokens below are the whole design system — colour,
 * type, spacing and shape — and nothing beneath :root should need editing to
 * change how the site looks.
 *
 * Poppins is served from this domain rather than Google's. Four weights in
 * two subsets is 52 KB, against two cross-origin DNS lookups, a connection to
 * a third party on every page load, and a face that arrives after the CSS has
 * already been parsed. latin-ext carries Albanian's e-diaeresis and
 * c-cedilla; unicode-range means an English page never fetches it.
 */

@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("fonts/poppins-400-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("fonts/poppins-400-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url("fonts/poppins-500-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url("fonts/poppins-500-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url("fonts/poppins-600-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url("fonts/poppins-600-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url("fonts/poppins-700-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:Poppins;
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url("fonts/poppins-700-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* The metric-matched fallbacks. Poppins ships with font-display:swap,
   which is right - the page must be readable before an 8 KB font
   arrives. The cost is that the first paint uses whatever the system
   offers and the second uses Poppins, and the two are not the same
   width: measured, Poppins sets 7.7% wider than Arial and 14.8% wider
   than Roboto, enough to re-wrap a heading and shift 2,032px of page
   beneath it. Each face below is a font the browser was going to fall
   back to anyway, re-declared with Poppins' metrics so the swap moves
   nothing. Four, not one: two metric groups, and a bold in each,
   because a face with no font-weight descriptor claims 400 only and
   everything heavier gets synthesised at an unmeasured width. */

@font-face{
  font-family:"Poppins Fallback";
  font-weight:100 500;
  src:local("Arial"),local("Helvetica"),local("Liberation Sans"),local("Arimo");
  size-adjust:107.7%;
  ascent-override:97.5%;
  descent-override:32.5%;
  line-gap-override:9.3%;
}
@font-face{
  font-family:"Poppins Fallback";
  font-weight:501 900;
  src:local("Arial Bold"),local("Arial-BoldMT"),local("Helvetica Bold"),local("Liberation Sans Bold"),local("Arimo Bold");
  size-adjust:105.7%;
  ascent-override:99.3%;
  descent-override:33.1%;
  line-gap-override:9.5%;
}
@font-face{
  font-family:"Poppins Fallback Narrow";
  font-weight:100 500;
  src:local("Roboto"),local("Segoe UI"),local("Noto Sans"),local("DejaVu Sans");
  size-adjust:114.8%;
  ascent-override:91.4%;
  descent-override:30.5%;
  line-gap-override:8.7%;
}
@font-face{
  font-family:"Poppins Fallback Narrow";
  font-weight:501 900;
  src:local("Roboto Bold"),local("Segoe UI Bold"),local("Noto Sans Bold"),local("DejaVu Sans Bold");
  size-adjust:113.6%;
  ascent-override:92.4%;
  descent-override:30.8%;
  line-gap-override:8.8%;
}

:root{
  /* Brand. The red is the only saturated colour on the site, which is what
     keeps it meaning something. */
  --red:#D22027;
  --red-dark:#A31118;
  --red-wash:rgba(210,32,39,.08);

  /* Ink and greys. Not pure black: #111114 carries a trace of blue, which
     reads as considered where #000 reads as a default. */
  --ink:#111114;
  --ink-soft:#3a3a42;
  --grey:#5c5c66;
  --line:#ececf0;
  --surface:#f7f7f9;
  --bg:#ffffff;

  /* Shape */
  --radius:22px;
  --radius-sm:14px;
  --radius-pill:999px;
  --shadow:0 6px 24px rgba(17,17,20,.06);
  --shadow-hover:0 18px 44px rgba(210,32,39,.14);

  /* Measure and rhythm */
  --wrap:1200px;
  --gutter:clamp(20px,4vw,40px);
  --section:clamp(64px,9vw,120px);

  --font:Poppins,"Poppins Fallback","Poppins Fallback Narrow",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}

/* ---- Reset, only what is actually needed ---------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font);
  font-size:17px;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
img,svg,video{max-width:100%;height:auto;display:block}
a{color:inherit}
button{font:inherit}
h1,h2,h3,h4{margin:0;line-height:1.12;letter-spacing:-.02em;font-weight:600;text-wrap:balance}
p{margin:0 0 1em}
ul,ol{margin:0;padding:0}

/* ---- Type scale ------------------------------------------------------
   Fluid between a phone and a large desktop, so nothing needs a breakpoint
   just to stop a headline overwhelming its column. */
.t-display{font-size:clamp(2.6rem,6vw,4.4rem);font-weight:700}
.t-h2{font-size:clamp(1.9rem,3.6vw,3rem)}
.t-h3{font-size:clamp(1.2rem,1.7vw,1.45rem);font-weight:600}
.t-lead{font-size:clamp(1.05rem,1.4vw,1.2rem);color:var(--grey);line-height:1.7}
.t-small{font-size:.875rem;color:var(--grey)}

.t-eyebrow{
  display:inline-block;
  font-size:.75rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--red);
}

/* ---- Layout ---------------------------------------------------------- */
.wrap{width:min(var(--wrap),100% - var(--gutter) * 2);margin-inline:auto}
.section{padding-block:var(--section)}
.section--tight{padding-block:calc(var(--section) * .6)}
.section--surface{background:var(--surface)}

.stack > * + *{margin-top:var(--stack,1rem)}

/* ---- Buttons ---------------------------------------------------------
   Two only: the thing to do, and the thing beside it. A third weight of
   button is nearly always a sign the page is asking too much at once. */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:.55rem;
  min-height:52px;
  padding:0 1.75rem;
  border:1px solid transparent;
  border-radius:var(--radius-pill);
  background:var(--red);
  color:#fff;
  font-weight:600;
  font-size:.975rem;
  text-decoration:none;
  cursor:pointer;
  transition:background .16s ease,transform .16s ease,box-shadow .16s ease;
}
.btn:hover{background:var(--red-dark);transform:translateY(-1px);box-shadow:var(--shadow-hover)}
.btn:active{transform:translateY(0)}

.btn--ghost{
  background:transparent;
  color:var(--ink);
  border-color:var(--line);
}
.btn--ghost:hover{background:var(--surface);border-color:var(--ink);box-shadow:none}

/* ---- Focus -----------------------------------------------------------
   Visible, and only for keyboards. A focus ring that also fires on click
   gets designed away, and then nobody has one. */
:focus-visible{outline:2px solid var(--red);outline-offset:3px;border-radius:4px}

/* ---- Motion ----------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important;scroll-behavior:auto !important}
}

.screen-reader-text{
  position:absolute!important;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;
}


/* ===================================================================
   HEADER, FOOTER, NAV, SEARCH, 404
   (was assets/parts/chrome.css)
   =================================================================== */

/*
 * Site chrome — header, navigation, language switcher, footer, search, 404.
 *
 * Merges into app.css and loads after it. Every colour, radius and measure
 * below comes from the tokens already declared in app.css :root; nothing here
 * declares a new one.
 *
 * The navigation exists once in the document. Above 1024px it is a row in the
 * header bar; below, the same element becomes a panel under it. There is no
 * second copy of the menu for mobile, which is why the call to action and the
 * language switcher sit inside the nav rather than beside it.
 */

/* ---- Skip link ------------------------------------------------------- */
/* .screen-reader-text is declared !important in app.css, and half the plugin
   ecosystem ships its own copy of it with a top of -10000em and a legacy clip.
   Un-hiding on focus therefore has to be just as loud, and has to undo the
   legacy properties this theme never sets but a plugin might. */
.site-content:focus{outline:none}

.skip-link:focus{
  clip:auto!important;
  clip-path:none!important;
  width:auto!important;height:auto!important;
  margin:0!important;overflow:visible!important;
  top:.6rem!important;left:.6rem!important;
  z-index:100;
  padding:.7rem 1.1rem;
  background:var(--ink);
  color:#fff;
  border-radius:var(--radius-pill);
  font-size:.9rem;font-weight:600;
  line-height:1;
  text-decoration:none;
}

/* ---- Icons ------------------------------------------------------------
   Sized in CSS as well as in the attributes: app.css sets height:auto on every
   svg, which leaves an icon's height to be inferred, and an inferred height is
   one more thing that can come out as zero inside a flex or grid parent. */
.aa-icon{flex:0 0 auto;width:20px;height:20px}

/* ---- Header ----------------------------------------------------------- */
.site-header{
  position:sticky;top:0;z-index:60;
  background:var(--bg);
  border-bottom:1px solid var(--line);
}
@supports (backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px)){
  .site-header{
    background:color-mix(in srgb,var(--bg) 86%,transparent);
    -webkit-backdrop-filter:saturate(1.6) blur(12px);
    backdrop-filter:saturate(1.6) blur(12px);
  }
}

.site-header__inner{
  display:flex;align-items:center;gap:1.25rem;
  min-height:74px;
}

/* ---- Brand ------------------------------------------------------------ */
.site-brand{flex:0 0 auto;display:flex;align-items:center}
.site-brand .custom-logo-link{display:flex;align-items:center;min-height:44px;line-height:0}
.site-brand .custom-logo{width:auto;height:40px}

.site-brand__mark{
  display:inline-flex;align-items:baseline;gap:.22rem;
  min-height:44px;padding-block:.55rem;
  font-size:1.15rem;font-weight:700;letter-spacing:-.025em;
  color:var(--ink);text-decoration:none;white-space:nowrap;
}
.site-brand__dot{width:6px;height:6px;border-radius:50%;background:var(--red)}

/* ---- Navigation, desktop ---------------------------------------------- */
.site-nav{
  flex:1 1 auto;
  display:flex;align-items:center;justify-content:flex-end;
  gap:clamp(1rem,2.4vw,2.25rem);
}
.site-nav__list{
  display:flex;align-items:center;
  gap:clamp(.6rem,1.6vw,1.6rem);
  list-style:none;margin:0;padding:0;
}
.site-nav__list a{
  display:flex;align-items:center;
  min-height:44px;padding:0 .25rem;
  font-size:.95rem;font-weight:500;
  color:var(--ink);text-decoration:none;
  white-space:nowrap;
  position:relative;
  transition:color .16s ease;
}
.site-nav__list a::after{
  content:"";
  position:absolute;left:.25rem;right:.25rem;bottom:11px;
  height:2px;border-radius:2px;background:var(--red);
  transform:scaleX(0);transform-origin:left;
  transition:transform .18s ease;
}
.site-nav__list a:hover{color:var(--red)}
.site-nav__list a:hover::after{transform:scaleX(1)}
.site-nav__list .current-menu-item > a,
.site-nav__list .current_page_item > a,
.site-nav__list .current-menu-ancestor > a{color:var(--red)}
.site-nav__list .current-menu-item > a::after,
.site-nav__list .current_page_item > a::after,
.site-nav__list .current-menu-ancestor > a::after{transform:scaleX(1)}

/* Sub-menus are not opened on hover in the header; depth is 1 by design. */
.site-nav__list .sub-menu{display:none}

.site-nav__extra{
  display:flex;align-items:center;
  gap:.85rem;flex:0 0 auto;
}
.site-nav__cta{min-height:44px;padding:0 1.35rem;font-size:.9rem}

/* ---- Burger ------------------------------------------------------------ */
.nav-toggle{
  display:none;
  width:44px;height:44px;flex:0 0 auto;
  align-items:center;justify-content:center;
  margin-inline-start:auto;
  padding:0;border:0;border-radius:var(--radius-pill);
  background:transparent;color:var(--ink);cursor:pointer;
}
.nav-toggle:hover{background:var(--surface)}
.nav-toggle__bars{display:block;width:22px;height:16px;position:relative}
.nav-toggle__bars span{
  position:absolute;left:0;
  width:100%;height:2px;border-radius:2px;
  background:currentColor;
  transition:transform .2s ease,opacity .15s ease,top .2s ease;
}
.nav-toggle__bars span:nth-child(1){top:0}
.nav-toggle__bars span:nth-child(2){top:7px}
.nav-toggle__bars span:nth-child(3){top:14px}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(1){top:7px;transform:rotate(45deg)}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(2){opacity:0}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(3){top:7px;transform:rotate(-45deg)}

/* ---- Language switcher -------------------------------------------------
   Renders nothing at all while the site has one language, so none of this is
   on the page today. */
.aa-lang__list{display:flex;align-items:center;gap:.25rem;list-style:none;margin:0;padding:0}
.aa-lang__link{
  display:inline-flex;align-items:center;gap:.4rem;
  min-height:44px;padding:0 .55rem;
  border-radius:var(--radius-pill);
  font-size:.75rem;font-weight:600;letter-spacing:.06em;
  color:var(--grey);text-decoration:none;
  transition:background .16s ease,color .16s ease;
}
.aa-lang__link:hover{background:var(--surface);color:var(--ink)}
.aa-lang__link[aria-current]{color:var(--ink)}
.aa-lang__link[aria-current] .aa-flag{box-shadow:0 0 0 2px var(--red)}
.aa-flag{
  display:block;width:22px;height:16px;
  border-radius:3px;
  box-shadow:0 0 0 1px var(--line);
}
.aa-flag--code{
  display:grid;place-items:center;
  width:auto;min-width:22px;height:16px;padding:0 4px;
  font-size:.62rem;font-weight:700;
  background:var(--surface);color:var(--grey);
}
/* The plugin's own switcher, if we ever have to fall back to it. */
.aa-lang--plugin > *{display:flex;align-items:center;gap:.4rem}
.aa-lang--plugin img{width:22px;height:16px;border-radius:3px}

/* ---- Navigation, below 1024 -------------------------------------------- */
@media (max-width:1023.98px){
  .site-header__inner{min-height:62px;gap:.75rem;position:relative}
  .site-brand .custom-logo{height:32px}

  .nav-toggle{display:flex}

  .site-nav{
    display:none;
    position:absolute;top:100%;left:calc(var(--gutter) * -1);right:calc(var(--gutter) * -1);
    flex-direction:column;align-items:stretch;justify-content:flex-start;
    gap:0;
    max-height:calc(100vh - 62px);
    max-height:calc(100dvh - 62px);
    overflow-y:auto;
    padding:.5rem var(--gutter) 1.5rem;
    background:var(--bg);
    border-bottom:1px solid var(--line);
    box-shadow:var(--shadow);
  }
  .site-nav.is-open{display:flex}

  .site-nav__list{flex-direction:column;align-items:stretch;gap:0}
  .site-nav__list li{border-bottom:1px solid var(--line)}
  .site-nav__list a{
    min-height:52px;padding:0;
    font-size:1.05rem;font-weight:500;
  }
  .site-nav__list a::after{display:none}

  .site-nav__extra{
    flex-direction:column-reverse;align-items:stretch;
    gap:1rem;margin-top:1.35rem;
  }
  .site-nav__cta{width:100%;min-height:52px}
  .aa-lang__list{justify-content:center}
  .aa-lang__link{padding:0 .75rem}
}

/* ---- 7. Footer ---------------------------------------------------------
   Replaces the `---- Footer ----` block inside the chrome section of app.css
   (everything from `.site-footer{` down to `.site-footer__legal-list a:hover`).
   Drop that block when merging this one in; the `.site-footer__menu` rules it
   contained have no markup left to style, because the footer no longer renders
   a wp_nav_menu.

   Every colour, radius, shadow and measure below comes from the tokens at the
   top of app.css. This file declares none of its own.

   The shape: a brand block on the left — mark, one sentence, three contact
   details, three social buttons — and the site's columns to its right, divided
   from it by a hairline from 900px up. Below both, a bar carrying the copyright
   and the legal pages.

   The composition problem this fixes was not spacing. Two of the four columns
   were headings over white space, because they were generated from a menu whose
   top-level items had no children. Columns now come from inc/footer.php, which
   drops any that would be empty, so the grid below can be a plain grid: it
   never has to disguise a hole.

   Rhythm. One vertical unit runs through the whole footer: every row that can
   be clicked is 44px tall, which is both the minimum tap target and — at this
   type size — a comfortable line spacing for a list of links. The brand's
   contact rows, the column headings, the links, the legal links and the
   copyright are all on it, so the two halves of the footer line up without a
   single hand-tuned margin. */

.site-footer{
  /* No margin. A margin here is a strip of body colour between the last
     section and the footer, which reads as a gap rather than as space -
     most obviously when the section above is also --surface, where it cut a
     white band through two areas of the same grey. The footer's own padding
     supplies the breathing room; the hairline supplies the division. */
  margin-top:0;
  background:var(--surface);
  border-top:1px solid var(--line);
}

.site-footer__inner{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:clamp(2.75rem,5vw,3.5rem);
  padding-block:clamp(3rem,6vw,4.75rem);
}

/* The brand column is given a range rather than a width so the blurb keeps a
   readable measure on a 1440 screen without squeezing the columns beside it. */
@media (min-width:900px){
  .site-footer__inner{
    grid-template-columns:minmax(15rem,20rem) minmax(0,1fr);
    column-gap:0;
  }
}

/* ---- Brand ------------------------------------------------------------- */
/* aa_logo() returns either the custom logo — wrapped in a <picture> when a WebP
   twin exists — or the text wordmark. Both shapes are sized here, so the footer
   can show the mark smaller than the header does without either of them knowing
   which one came back. */
.site-footer__mark{display:flex;align-items:center;min-height:44px}
.site-footer__mark picture{display:block}
.site-footer__brand .custom-logo-link{display:flex;align-items:center;min-height:44px;line-height:0}
.site-footer__brand .custom-logo{width:auto;height:38px}

.site-footer__blurb{
  margin:1.25rem 0 0;
  max-width:36ch;
  font-size:.94rem;
  line-height:1.7;
  color:var(--grey);
  text-wrap:pretty;
}

.site-footer__contact{list-style:none;margin:1.5rem 0 0;padding:0;display:grid}
.site-footer__contact li{display:flex;align-items:center;gap:.7rem;min-height:44px;font-size:.94rem}
.site-footer__contact .aa-icon{width:18px;height:18px;color:var(--red)}
.site-footer__contact a,
.site-footer__contact span{display:flex;align-items:center;min-height:44px}
.site-footer__contact a{color:var(--ink);text-decoration:none;transition:color .16s ease}
.site-footer__contact a:hover{color:var(--red)}
.site-footer__contact span{color:var(--grey)}

.site-footer__social{list-style:none;margin:1.75rem 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem}
.site-footer__social a{
  display:grid;place-items:center;
  width:44px;height:44px;
  border:1px solid var(--line);
  border-radius:var(--radius-pill);
  background:var(--bg);
  color:var(--ink);
  transition:color .16s ease,border-color .16s ease,transform .16s ease,box-shadow .16s ease;
}
.site-footer__social a:hover{
  color:var(--red);
  border-color:var(--red);
  transform:translateY(-2px);
  box-shadow:var(--shadow);
}
/* The global focus ring sets border-radius:4px, which would square a round
   button for as long as it held focus. Keep the pill. */
.site-footer__social a:focus-visible{border-radius:var(--radius-pill)}

/* ---- Columns ----------------------------------------------------------- */
/* A hairline rather than a gap does the dividing from 900px up: it reads as
   structure at a glance, and it costs no horizontal space on the breakpoint
   where the columns are tightest. */
@media (min-width:900px){
  .site-footer__nav{
    border-inline-start:1px solid var(--line);
    padding-inline-start:clamp(2.25rem,4vw,4rem);
  }
}

/* Four fixed steps, not auto-fit. auto-fit decides how many columns fit and
   leaves whatever is left over stranded on a row of its own — with four
   columns that is a lone one under a row of three. Stepping 1 → 2 → 4 keeps
   every row complete at every width. */
.site-footer__cols{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:clamp(1.75rem,3vw,2.5rem) clamp(1.25rem,2.5vw,2rem);
  align-content:start;
}
@media (min-width:560px){
  .site-footer__cols{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (min-width:1100px){
  .site-footer__cols{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* The heading is set as a label, not as a heading: small, spaced and upper
   case, so it reads as the top of a list rather than as a section title
   competing with the page above it. h2 in app.css sets a negative letter
   spacing, which is right for a headline and wrong for capitals. */
.site-footer__col-title{
  margin:0;
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.14em;
  text-transform:uppercase;
  line-height:1.2;
  color:var(--ink);
}
.site-footer__col-title > *{
  display:inline-flex;
  align-items:center;
  min-height:44px;
  color:inherit;
  text-decoration:none;
}
.site-footer__col-title a{transition:color .16s ease}
.site-footer__col-title a:hover{color:var(--red)}

.site-footer__list{list-style:none;margin:0;padding:0;display:grid}
.site-footer__list a{
  display:flex;
  align-items:center;
  min-height:44px;
  
  font-size:.92rem;
  line-height:1.35;
  color:var(--grey);
  text-decoration:none;
  transition:color .16s ease;
}
.site-footer__list a:hover{color:var(--red)}

/* ---- Bottom bar --------------------------------------------------------- */
/* Copyright left, legal right, and on a phone the two stack in that order
   rather than centring — a centred bar looks arranged, and this one is the
   quietest thing on the page. */
.site-footer__bar{border-top:1px solid var(--line)}
.site-footer__bar-inner{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between;
  gap:0 1.5rem;
  min-height:64px;
  padding-block:.5rem;
}
.site-footer__copy{
  margin:0;
  display:flex;align-items:center;min-height:44px;
  font-size:.85rem;color:var(--grey);
}
.site-footer__legal-list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:0 1.5rem}
.site-footer__legal-list a{
  display:flex;align-items:center;min-height:44px;
  font-size:.85rem;color:var(--grey);text-decoration:none;
  transition:color .16s ease;
}
.site-footer__legal-list a:hover{color:var(--red)}


/* ---- Search form -------------------------------------------------------- */
.search-form{
  display:flex;align-items:center;gap:.5rem;
  width:min(420px,100%);
  padding:.3rem .3rem .3rem 1.1rem;
  background:var(--bg);
  border:1px solid var(--line);
  border-radius:var(--radius-pill);
  transition:border-color .16s ease;
}
.search-form:focus-within{border-color:var(--ink)}
.search-form__field{
  flex:1 1 auto;min-width:0;
  border:0;background:none;
  font:inherit;font-size:.95rem;color:var(--ink);
  padding:.55rem 0;
}
.search-form__field:focus{outline:none}
.search-form__submit{
  display:grid;place-items:center;flex:0 0 auto;
  width:44px;height:44px;padding:0;
  border:0;border-radius:var(--radius-pill);
  background:var(--red);color:#fff;cursor:pointer;
  transition:background .16s ease;
}
.search-form__submit:hover{background:var(--red-dark)}

/* ---- 404 ---------------------------------------------------------------- */
.error-404__inner{
  max-width:34rem;
  display:grid;justify-items:start;gap:1.1rem;
}
.error-404 .search-form{margin-block:.4rem}
.error-404__inner .t-lead{margin:0}
.error-404__actions{display:flex;flex-wrap:wrap;gap:.75rem;margin:.5rem 0 0}


/* ===================================================================
   INNER PAGES - prose, heroes, offer cards, closing strip
   (was assets/parts/pages.css)
   =================================================================== */

/*
 * Pages — hero, prose, offer cards, galleries, contact.
 *
 * Merges into app.css and loads after it. Every colour, radius and measure
 * below comes from the tokens already declared in app.css :root; nothing here
 * declares a new one.
 *
 * The rule that shapes this file: a page's copy lives in post_content as
 * ordinary HTML — h2, p, ul, a — and this stylesheet is what makes that
 * readable. A handful of classes (aa-grid, aa-plan, aa-gallery, aa-video)
 * exist because a price card and a logo wall are genuinely different objects
 * from a paragraph, not because the markup needed padding. The contact block
 * is not among them: that one belongs to inc/contact.php, and these pages
 * call it rather than drawing a second version of it.
 */

/* ---- Page hero -------------------------------------------------------
   Title, optional standfirst, optional illustration. The illustration keeps
   its own aspect ratio — these are the owner's drawings and cropping them to
   a house ratio would cut the subject out of half of them. Width and height
   attributes on the img are what reserve the space, so nothing shifts. */

.aa-phero{
  padding-block:clamp(52px,7vw,96px) 0;
}
.aa-phero__inner{
  display:grid;
  gap:clamp(28px,4vw,64px);
  align-items:center;
}
.aa-phero__text{max-width:34ch}
.aa-phero__lead{max-width:56ch;margin-top:1.1rem;margin-bottom:0}
.aa-phero__eyebrow{margin-bottom:1rem}

/* Capped rather than fluid: stacked under the title on a tablet, a drawing
   at the full width of the column reads as a banner and pushes the copy off
   the screen. */
.aa-phero__media{
  max-width:440px;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius);
  padding:clamp(18px,3vw,34px);
  display:grid;
  place-items:center;
}
.aa-phero__media img{width:100%;height:auto}

@media (min-width:900px){
  .aa-phero--media .aa-phero__inner{grid-template-columns:minmax(0,1fr) minmax(0,440px)}
  .aa-phero__text{max-width:none}
}

/* A hairline under the hero, so the page has a shoulder rather than a seam.
   Only where the body that follows is on white — on --surface the colour
   change is the divider. */
.aa-page-body{padding-block:clamp(44px,5.5vw,80px)}
.aa-page-body--top{border-top:1px solid var(--line)}

/* ---- Prose -----------------------------------------------------------
   Measure is set on the children rather than the container, so a paragraph
   stays at a readable 68 characters while a card grid or a gallery below it
   still uses the full column. */

.aa-prose{color:var(--ink-soft)}
.aa-prose > *{max-width:68ch}
.aa-prose > .aa-grid,
.aa-prose > .aa-gallery,
.aa-prose > .aa-video,
.aa-prose > figure,
.aa-prose > hr{max-width:none}

.aa-prose > :first-child{margin-top:0}
.aa-prose > :last-child{margin-bottom:0}

.aa-prose h2{
  font-size:clamp(1.45rem,2.6vw,1.95rem);
  color:var(--ink);
  margin:1.9em 0 .5em;
}
.aa-prose h3{
  font-size:clamp(1.15rem,1.7vw,1.35rem);
  color:var(--ink);
  margin:1.7em 0 .45em;
}
.aa-prose h4{
  font-size:1.02rem;
  color:var(--ink);
  margin:1.8em 0 .4em;
}
.aa-prose h2 + h3,
.aa-prose h3 + h4{margin-top:1.1em}

.aa-prose p{margin:0 0 1.15em}
.aa-prose strong{color:var(--ink);font-weight:600}

/* Prose links only. A component dropped into the copy — the contact block,
   for one — brings its own look, and a red underline inherited from here
   would fight it. The exclusion is wrapped in :where() so that skipping the
   block costs no specificity, and .btn below still wins as it always did. */
.aa-prose a:not(:where(.aa-cblock a)){
  color:var(--red);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:.18em;
  transition:color .16s ease;
}
.aa-prose a:not(:where(.aa-cblock a)):hover{color:var(--red-dark)}

.aa-prose ul,
.aa-prose ol{margin:0 0 1.3em;padding-left:1.35em}
.aa-prose ul{list-style:disc}
.aa-prose ol{list-style:decimal}
.aa-prose li{margin-bottom:.45em}
.aa-prose li::marker{color:var(--red)}
.aa-prose li > ul,
.aa-prose li > ol{margin:.5em 0 .2em}
.aa-prose li > p{margin:0 0 .4em}

.aa-prose blockquote{
  margin:2em 0;
  padding:.15em 0 .15em 1.5rem;
  border-left:3px solid var(--red);
  color:var(--ink);
  font-size:clamp(1.1rem,1.5vw,1.25rem);
  font-weight:500;
  line-height:1.55;
}
.aa-prose blockquote p:last-child{margin-bottom:0}

.aa-prose hr{
  border:0;
  border-top:1px solid var(--line);
  margin:2.8em 0;
}

.aa-prose figure{margin:2em 0}
.aa-prose figure img{border-radius:var(--radius-sm)}
.aa-prose figcaption{margin-top:.7rem;font-size:.875rem;color:var(--grey)}

/* Tables are rare here, but a table that cannot scroll is a table that
   breaks the page on a phone. */
.aa-prose table{
  display:block;
  overflow-x:auto;
  width:100%;
  border-collapse:collapse;
  font-size:.95rem;
  margin:0 0 1.5em;
}
.aa-prose th,
.aa-prose td{
  text-align:left;
  padding:.7rem 1rem;
  border-bottom:1px solid var(--line);
  vertical-align:top;
}
.aa-prose th{color:var(--ink);font-weight:600;white-space:nowrap}

.aa-prose .btn{text-decoration:none;color:#fff}
.aa-prose .btn--ghost{color:var(--ink)}
.aa-prose .btn:hover{color:#fff}
.aa-prose .btn--ghost:hover{color:var(--ink)}

/* A document — terms, a policy — wants one narrow column and nothing else. */
.aa-prose--doc > *{max-width:66ch}

/* ---- Offer cards -----------------------------------------------------
   A price, what it buys, and the way to ask for it. Same object on every
   service page, so it is the same card everywhere. */

.aa-grid{
  display:grid;
  gap:clamp(16px,2vw,26px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr));
  margin:2.2em 0;
}
.aa-grid > *{max-width:none}

/* A full-width offer under a row of three: without this the auto-fit grid
   opens a fourth track that only the wide card fills, and the row above ends
   in a hole. */
.aa-grid:has(> .aa-plan--lead){grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}

.aa-plan{
  display:flex;
  flex-direction:column;
  gap:.85rem;
  padding:clamp(24px,3vw,34px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--bg);
  transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease;
}
.aa-plan:hover{border-color:transparent;box-shadow:var(--shadow);transform:translateY(-2px)}

/* One card on its own should not stretch to a thousand pixels just because
   the grid can. */
.aa-grid > .aa-plan:only-child{max-width:440px}

.aa-plan h3{margin:0;font-size:1.2rem;color:var(--ink)}
.aa-plan > p{margin:0;font-size:.975rem}

/* The button is the last thing in a card, and it sits on the floor so that
   cards of different lengths still line their buttons up. */
.aa-plan > p:last-child{margin-top:auto;padding-top:.35rem}

/* Elementor's price boxes carry a small label above the figure — "Only",
   "Starting from". It is a label, not a heading. */
.aa-plan .aa-plan__label{
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--red);
  margin-bottom:-.4rem;
}

.aa-plan .aa-plan__price{
  font-size:clamp(1.75rem,2.6vw,2.15rem);
  font-weight:700;
  line-height:1.05;
  letter-spacing:-.02em;
  color:var(--ink);
}
.aa-plan .aa-plan__price span{
  display:block;
  margin-top:.35rem;
  font-size:.85rem;
  font-weight:500;
  letter-spacing:0;
  color:var(--grey);
}

/* Two prices — rent and buy — on one card, so the choice is visible without
   a toggle that needs script to work. */
.aa-plan__prices{
  display:grid;
  gap:1rem;
  margin:0;
  padding:1rem 0 0;
  border-top:1px solid var(--line);
  grid-template-columns:repeat(auto-fit,minmax(110px,1fr));
}
.aa-plan__prices > div{margin:0}
.aa-plan__prices dt{
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--red);
  margin-bottom:.35rem;
}
.aa-plan__prices dd{
  margin:0;
  font-size:1.45rem;
  font-weight:700;
  line-height:1.1;
  letter-spacing:-.02em;
  color:var(--ink);
}
.aa-plan__prices dd span{
  display:block;
  margin-top:.3rem;
  font-size:.8rem;
  font-weight:500;
  letter-spacing:0;
  color:var(--grey);
}

.aa-plan ul{
  list-style:none;
  margin:0;
  padding:1rem 0 0;
  border-top:1px solid var(--line);
}
.aa-plan li{
  position:relative;
  margin:0 0 .55rem;
  padding-left:1.7rem;
  font-size:.95rem;
  color:var(--grey);
}
.aa-plan li:last-child{margin-bottom:0}
.aa-plan li::marker{content:none}
.aa-plan li::before{
  content:"";
  position:absolute;
  left:0;
  top:.42em;
  width:1rem;
  height:1rem;
  background:var(--red);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='%23000' d='M7.6 14.7 3.3 10.4l1.4-1.4 2.9 2.9 7.7-7.7 1.4 1.4z'/%3E%3C/svg%3E") no-repeat center/contain;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='%23000' d='M7.6 14.7 3.3 10.4l1.4-1.4 2.9 2.9 7.7-7.7 1.4 1.4z'/%3E%3C/svg%3E") no-repeat center/contain;
}

/* The demo QR code is the same address as the link above it. It belongs at
   the foot of the card at the size a phone camera needs, not at the top at
   the size of a photograph. */
.aa-plan .aa-qr{margin-top:auto;padding-top:.4rem}
.aa-plan .aa-qr img{max-width:112px}

.aa-plan figure{margin:0}
.aa-plan figure img{
  border-radius:var(--radius-sm);
  width:100%;
  height:auto;
  background:var(--surface);
}

/* The one offer a page wants read first. */
.aa-plan--lead{
  grid-column:1/-1;
  max-width:none;
  background:linear-gradient(to top,var(--red-wash),var(--bg));
}
@media (min-width:760px){
  .aa-plan--lead{
    display:grid;
    grid-template-columns:minmax(0,1fr) auto;
    align-items:center;
    column-gap:clamp(24px,4vw,56px);
  }
  .aa-plan--lead > *{grid-column:1}
  .aa-plan--lead > p:last-child{
    grid-column:2;
    grid-row:1/-1;
    align-self:center;
    margin-top:0;
    padding-top:0;
  }
}

/* ---- Embedded tour ----------------------------------------------------
   The 3D viewer is the product, so it stays. Lazy, and in a box that already
   knows its shape, so it costs nothing until it is scrolled to and moves
   nothing when it arrives. */

.aa-embed{margin:2em 0}
.aa-embed iframe{
  display:block;
  width:100%;
  height:auto;
  aspect-ratio:16/9;
  min-height:340px;
  border:0;
  border-radius:var(--radius);
  background:var(--surface);
}

/* ---- Galleries -------------------------------------------------------
   Two kinds: logos, which must never be cropped, and screenshots, which are
   already the right shape. Both tiles fix their own ratio so the grid does
   not reflow as images arrive. */

ul.aa-gallery{
  list-style:none;
  margin:2.2em 0;
  padding:0;
  display:grid;
  gap:clamp(12px,1.6vw,20px);
}
.aa-gallery li{margin:0}
.aa-gallery img{display:block}

ul.aa-gallery--logos{grid-template-columns:repeat(auto-fill,minmax(min(100%,175px),1fr))}
.aa-gallery--logos li{
  aspect-ratio:1;
  overflow:hidden;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
}
.aa-gallery--logos img{width:100%;height:100%;object-fit:contain}

ul.aa-gallery--shots{grid-template-columns:repeat(auto-fill,minmax(min(100%,190px),1fr))}
.aa-gallery--shots figure{margin:0}
.aa-gallery--shots img{
  width:100%;
  height:auto;
  aspect-ratio:3/4;
  object-fit:cover;
  border-radius:var(--radius-sm);
  background:var(--surface);
}
.aa-gallery--shots figcaption{
  margin-top:.65rem;
  font-size:.875rem;
  font-weight:500;
  color:var(--grey);
  text-align:center;
}

/* ---- Video ------------------------------------------------------------
   A manual page with six embedded players costs more than the manual is
   worth: each iframe is its own document, its own scripts, its own
   connections. These are links, drawn as players, that cost nothing until
   somebody wants to watch. */

.aa-video{margin:1.4em 0 2.4em}
.aa-video a{
  display:flex;
  align-items:center;
  gap:1rem;
  padding:1rem 1.4rem;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  color:var(--ink);
  font-weight:600;
  text-decoration:none;
  transition:border-color .16s ease,background .16s ease;
}
.aa-video a::before{
  content:"";
  flex:none;
  width:2.75rem;
  height:2.75rem;
  border-radius:var(--radius-pill);
  background:var(--red);
  -webkit-mask:none;
  mask:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M9 7.4v9.2c0 .5.5.8 1 .6l7.4-4.6a.7.7 0 0 0 0-1.2L10 6.8a.7.7 0 0 0-1 .6Z'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:center;
  background-size:1.5rem;
  transition:background-color .16s ease;
}
.aa-video a:hover{background:var(--bg);border-color:var(--ink)}
.aa-video a:hover::before{background-color:var(--red-dark)}

/* ---- Closing strip ----------------------------------------------------
   A rule and a label; the block inside it is inc/contact.php's and is styled
   there, so that the same three links look the same here, on the contact page
   and in the footer. */

.aa-close{border-top:1px solid var(--line)}
.aa-close__eyebrow{margin-bottom:1.4rem}

@media (max-width:560px){
  .aa-phero__text{max-width:none}
}


/* ===================================================================
   LANDING PAGE
   (was assets/parts/home.css)
   =================================================================== */

/*
 * The landing page.
 *
 * Loaded after app.css and it declares no tokens of its own: every colour,
 * radius, measure and rhythm value below resolves to something already in
 * :root. If a value here is a literal it is either a geometry constant (a
 * grid count, an aspect ratio) or an opacity, never a colour that could have
 * come from the palette.
 *
 * Section bands alternate white / --surface down the page, which is the only
 * device used to separate them: no rules, no wells, no gradients.
 */

/* ---- Shared to the page ---------------------------------------------- */

/* The heading block every section opens with: eyebrow, h2, and sometimes a
   lead, each held to its own measure so nothing runs the full 1200px.
   The measure is set per element rather than on the block because ch
   resolves against each element's own size: one width on the wrapper would
   hold a 48px headline and a 20px paragraph to the same pixel count, and
   only one of them would be right. */
.hp-head > * + *{margin-top:1rem}
.hp-head .t-eyebrow + *{margin-top:.85rem}
.hp-head p{margin-bottom:0}
.hp-head .t-h2{max-width:17ch}
.hp-head .t-lead{max-width:46ch}

.hp-icon{
  width:24px;height:24px;flex:none;
  stroke-width:1.6;
}
.hp-check{width:18px;height:18px;flex:none;stroke-width:2.2}
.hp-arrow{width:16px;height:16px;flex:none;stroke-width:1.8}

/* ---- 1. Hero ----------------------------------------------------------
   No image. The old build ran a particle canvas here; the largest thing on
   the page is now the headline itself, which is text the browser already
   has by the time it has the HTML. */

.hp-hero{padding-block:clamp(52px,7vw,96px) var(--section)}

.hp-hero__grid{display:grid;gap:clamp(40px,5vw,64px);align-items:start}
@media (min-width:900px){
  .hp-hero__grid{
    grid-template-columns:minmax(0,1.12fr) minmax(0,.88fr);
    gap:clamp(48px,6vw,96px);
    align-items:center;
  }
}

.hp-hero__title{margin-top:.7rem;max-width:13ch}
.hp-hero__lead{margin-top:1.4rem;max-width:54ch;margin-bottom:0}
.hp-hero__cta{margin-top:2.1rem}

/* The three promises, as a list of hairline-separated rows rather than three
   floating cards: it fills the right of the hero without pretending to be a
   second navigation. */
.hp-hero__list{list-style:none}
.hp-hero__item{
  display:flex;gap:1.1rem;align-items:flex-start;
  padding-block:1.2rem;
  border-top:1px solid var(--line);
}
.hp-hero__item:last-child{border-bottom:1px solid var(--line)}
.hp-hero__item .hp-icon{color:var(--red);margin-top:.2rem}
.hp-hero__name{display:block;font-weight:600;line-height:1.35}
.hp-hero__desc{display:block;margin-top:.15rem;color:var(--grey);font-size:.9375rem;line-height:1.5}

/* ---- 2. Proof ---------------------------------------------------------
   Eighteen client logos of eighteen different vintages, four of them white
   artwork on transparent. Flattening every one to a single ink silhouette is
   the only treatment that makes them all legible on one ground, and it stops
   the wall competing with the red. */

/* A supporting statement, not a peer of the section headings that follow:
   a step below t-h2's ceiling so the services headline keeps primacy. */
.hp-head .hp-proof__title{
  font-size:clamp(1.55rem,2.6vw,2.25rem);
  max-width:26ch;
}

.hp-logos{
  list-style:none;
  margin-top:clamp(36px,5vw,60px);
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(14px,2.4vw,26px);
}
@media (min-width:1000px){
  .hp-logos{grid-template-columns:repeat(6,minmax(0,1fr))}
}
.hp-logos li{
  display:flex;align-items:center;justify-content:center;
  height:clamp(60px,7.5vw,86px);   /* fixed box: the wall cannot shift */
  padding:.35rem;
}
.hp-logos img{
  width:auto;height:auto;
  max-width:100%;max-height:100%;
  object-fit:contain;
  filter:brightness(0) opacity(.5);
}

/* ---- 3. Services ------------------------------------------------------
   Ten cards do not divide into four columns, so the two that carry the most
   weight — the websites themselves and the ready-made systems — take two
   columns each. Twelve cells, three complete rows, and the emphasis lands
   where the business actually wants it. */

.hp-svc-grid{
  margin-top:clamp(40px,5vw,64px);
  display:grid;
  gap:clamp(14px,1.6vw,22px);
  grid-template-columns:minmax(0,1fr);
}
@media (min-width:620px){
  .hp-svc-grid{grid-template-columns:repeat(2,minmax(0,1fr))}

}
@media (min-width:1000px){
  .hp-svc-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}

.hp-svc{
  position:relative;
  display:flex;flex-direction:column;
  padding:clamp(22px,2.4vw,30px);
  background:var(--bg);
  border:1px solid var(--line);
  border-radius:var(--radius);
  transition:transform .16s ease,box-shadow .16s ease;
}
.hp-svc:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
.hp-svc:focus-within{outline:2px solid var(--red);outline-offset:3px}

.hp-svc__icon{color:var(--ink-soft);transition:color .16s ease}
.hp-svc:hover .hp-svc__icon{color:var(--red)}

.hp-svc__title{margin-top:1.15rem}
.hp-svc__title a{text-decoration:none}
/* One hit area for the whole card; the accessible name stays the title. */
.hp-svc__title a::after{content:"";position:absolute;inset:0;border-radius:var(--radius)}
.hp-svc__title a:focus-visible{outline:none}

.hp-svc__text{margin:.6rem 0 0;color:var(--grey);font-size:.9375rem;line-height:1.6}

/* The two-column cards earn the extra width with a step up in type, so the
   span reads as emphasis rather than as a card that ran out of words. */
@media (min-width:620px){


}

.hp-svc__more{
  margin-top:auto;padding-top:1.4rem;
  display:inline-flex;align-items:center;gap:.4rem;
  font-size:.875rem;font-weight:600;color:var(--grey);
  transition:color .16s ease;
}
.hp-svc:hover .hp-svc__more{color:var(--red)}
.hp-svc__more .hp-arrow{transition:transform .16s ease}
.hp-svc:hover .hp-svc__more .hp-arrow{transform:translateX(3px)}

/* ---- 4. Plans ---------------------------------------------------------
   Three columns of equal height with the button pinned to the foot, so the
   middle plan's ten lines against the others' six or seven does not leave
   two buttons floating. The middle one is the one being sold, so it is the
   one that goes dark. */

.hp-plans{
  margin-top:clamp(40px,5vw,64px);
  display:grid;
  gap:clamp(18px,2vw,26px);
  grid-template-columns:minmax(0,1fr);
}
@media (min-width:960px){
  .hp-plans{grid-template-columns:repeat(3,minmax(0,1fr))}
}

.hp-plan{
  display:flex;flex-direction:column;
  padding:clamp(26px,2.8vw,36px);
  background:var(--bg);
  border:1px solid var(--line);
  border-radius:var(--radius);
}
.hp-plan--feature{background:var(--ink);border-color:var(--ink);color:#fff}

.hp-plan__name{margin-top:.7rem;font-size:clamp(1.5rem,2vw,1.85rem)}
.hp-plan--feature .t-eyebrow{color:#fff;opacity:.62}

.hp-plan__list{list-style:none;margin-top:1.8rem;display:grid;gap:.72rem}
.hp-plan__list li{display:flex;gap:.7rem;align-items:flex-start;font-size:.9375rem;line-height:1.5}
.hp-plan__list .hp-check{color:var(--red);margin-top:.22rem}
.hp-plan--feature .hp-plan__list li{color:rgba(255,255,255,.84)}
.hp-plan--feature .hp-plan__list .hp-check{color:#fff;opacity:.7}

.hp-plan__cta{margin-top:auto;padding-top:2.1rem}
.hp-plan__cta .btn{width:100%}

/* ---- 5. Startups ------------------------------------------------------
   Three products, three marks, nothing written about any of them on the old
   page. The host name under each is the only honest caption available. */

.hp-startups__grid{
  margin-top:clamp(36px,4.5vw,56px);
  display:grid;
  gap:clamp(16px,2vw,24px);
  grid-template-columns:minmax(0,1fr);
}
@media (min-width:640px){
  .hp-startups__grid{grid-template-columns:repeat(3,minmax(0,1fr))}
}

.hp-startup{
  display:block;text-decoration:none;
  padding:clamp(22px,2.4vw,30px);
  /* White, not --surface: one of the three marks is a flat PNG with its own
     white ground baked in, and on any other colour that rectangle shows. */
  background:var(--bg);
  border:1px solid var(--line);
  border-radius:var(--radius);
  transition:background .16s ease,box-shadow .16s ease,transform .16s ease;
}
.hp-startup:hover{background:var(--surface);transform:translateY(-2px);box-shadow:var(--shadow)}

/* The mark is taken out of flow: a 4:3 illustration and a 15:1 wordmark
   otherwise each set their own card height, and aspect-ratio only floors a
   box, it does not cap it. */
.hp-startup__media{position:relative;display:block;aspect-ratio:16/9}
.hp-startup__media img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:contain;
}
.hp-startup__host{
  display:block;margin-top:1.1rem;
  font-size:.875rem;color:var(--grey);
  transition:color .16s ease;
}
.hp-startup:hover .hp-startup__host{color:var(--red)}


/* ===================================================================
   BLOG - index, archive, search, single
   (was assets/parts/blog.css)
   =================================================================== */

/*
 * AppAlbania — blog.
 *
 * A part of app.css, not a second stylesheet. It declares no tokens: colour,
 * radius, measure and rhythm all come from :root, which loads first.
 *
 * It also declares no prose. .aa-prose belongs to pages.css — paragraphs,
 * headings, lists, quotes, links and tables are already solved there and an
 * article is the same object as a page's copy. What is below only adds the
 * three things a page never needed: code, an anchor offset for the contents
 * list, and the classic editor's alignment classes, which exist in these nine
 * posts and nowhere else on the site.
 *
 * Three widths and no more. Text sits at 68ch, which is where a line stops
 * being work to track; the hero opens out to 980px so the photograph reads as
 * an image rather than an illustration; card grids and navigation take the
 * full 1200px wrap. Anything that looks like a fourth width is a mistake.
 */

/* -- View scaffolding ---------------------------------------------------- */

.aa-view{
  display:block;
  padding-top:clamp(20px,3.5vw,36px);
  padding-bottom:var(--section);
}

.aa-article__head,
.aa-article__body{
  width:min(68ch,100%);
  margin-inline:auto;
}

/* On an article the trail sits over the headline, not over the page. Left at
   the full wrap width it reads as a piece of the site chrome that happens to
   be inside the story. */
.aa-view--article .aa-crumbs{
  width:min(68ch,100%);
  margin-inline:auto;
}

/* A listing header reads against the left edge of the grid below it; the
   article, which has nothing beside it, is centred on its own column. */
.aa-page-head{
  width:min(60ch,100%);
  margin-bottom:clamp(36px,6vw,64px);
}

.aa-page-head__title,
.aa-article__title{
  font-size:clamp(2.1rem,4.4vw,3.3rem);
  font-weight:700;
  line-height:1.08;
  letter-spacing:-.025em;
  margin:.45rem 0 0;
  overflow-wrap:break-word;
}

.aa-page-head__intro{margin:1.1rem 0 0}
.aa-page-head .search-form{margin-top:1.6rem}

.aa-empty{padding-block:clamp(8px,2vw,24px)}
.aa-empty .search-form{margin-top:1.5rem}

.aa-dot{color:var(--line)}


/* -- Breadcrumbs ---------------------------------------------------------
   Yoast renders the trail and already publishes the BreadcrumbList behind it,
   so this styles whatever markup it hands over rather than assuming a
   structure. The padding is what carries the links past a 44px touch target. */

/* The size lives on the inner element, not the nav, so that the nav's own ch
   measure is the same one the article column uses — otherwise a 14px ch makes
   68ch 120px narrower here than it is over the headline. */
.aa-crumbs{color:var(--grey)}
.aa-crumbs__inner{
  font-size:.875rem;
  line-height:1.5;
}
.aa-crumbs a{
  display:inline-block;
  padding-block:.75rem;
  color:var(--grey);
  text-decoration:none;
}
.aa-crumbs a:hover{
  color:var(--red);
  text-decoration:underline;
  text-underline-offset:.2em;
}
.aa-crumbs [aria-current="page"],
.aa-crumbs .breadcrumb_last{color:var(--ink)}
.aa-crumbs__sep{
  padding-inline:.35rem;
  color:var(--line);
}


/* -- Card grid ------------------------------------------------------------
   One column, then two, then three. The breakpoints are where the cards start
   looking cramped, not where a device happens to be. Named .aa-cards, not
   .aa-grid: pages.css already owns .aa-grid for the offer cards inside a
   page's copy, and they are a different object with a different rhythm. */

.aa-cards{
  display:grid;
  grid-template-columns:1fr;
  gap:clamp(28px,3.4vw,40px);
}

@media (min-width:700px){
  .aa-cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}

@media (min-width:1040px){
  .aa-cards{grid-template-columns:repeat(3,minmax(0,1fr))}
}


/* -- Card -----------------------------------------------------------------
   The title link is stretched over the whole card, so the card is one target
   and one entry in the accessibility tree — not an image link and a title link
   pointing at the same place. */

.aa-card{
  position:relative;
  display:flex;
  flex-direction:column;
  min-width:0;
}

.aa-card__media{
  aspect-ratio:3/2;
  overflow:hidden;
  border-radius:var(--radius);
  background:var(--surface);
}
.aa-card__media img{
  width:100%;
  height:100%;
  object-fit:cover;
  transition:transform .5s cubic-bezier(.2,.6,.2,1);
}
.aa-card:hover .aa-card__media img{transform:scale(1.04)}

.aa-card__body{
  display:flex;
  flex-direction:column;
  flex:1;
  padding-top:1.15rem;
}
/* A result with no picture — a page, usually — should be a short card, not a
   tall one with a hole in it. Without this the meta line is pushed to the foot
   of a row sized by its neighbours' photographs. */
.aa-card--bare{align-self:start}
.aa-card--bare .aa-card__body{padding-top:0}
.aa-card--bare .aa-card__meta{
  margin-top:1.1rem;
  padding-top:0;
}

.aa-card__title{
  font-size:1.15rem;
  line-height:1.32;
  letter-spacing:-.015em;
  overflow-wrap:break-word;
}
/* The negative margin cancels the padding, so the padding buys nothing but
   height: a one-line title still gives the link a 44px box of its own, which
   is what an audit measures — it cannot see the stretched hit area. */
.aa-card__link{
  display:inline-block;
  padding-block:.7rem;
  margin-block:-.7rem;
  text-decoration:none;
  transition:color .16s ease;
}
.aa-card__link::after{
  content:"";
  position:absolute;
  inset:0;
  border-radius:var(--radius);
}
.aa-card:hover .aa-card__link{color:var(--red)}

.aa-card__excerpt{
  margin:.6rem 0 0;
  color:var(--grey);
  font-size:.9375rem;
  line-height:1.6;
}

/* Pushed to the foot so meta lines align across a row whatever the titles do. */
.aa-card__meta{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:.45rem;
  margin:auto 0 0;
  padding-top:1.1rem;
  color:var(--grey);
  font-size:.8125rem;
}


/* -- Lead card ------------------------------------------------------------
   The most recent post, given the room it earns. Below 760px it is simply a
   card; there is no width at which two columns of this would be readable. */

.aa-card--lead{grid-column:1/-1}

@media (min-width:760px){
  .aa-card--lead{
    display:grid;
    grid-template-columns:1.15fr 1fr;
    align-items:center;
    gap:clamp(28px,3.4vw,40px);
  }
  .aa-card--lead .aa-card__body{
    padding-top:0;
    justify-content:center;
  }
  .aa-card--lead .aa-card__title{
    font-size:clamp(1.5rem,2.4vw,1.95rem);
    line-height:1.2;
  }
  .aa-card--lead .aa-card__excerpt{
    font-size:1rem;
    margin-top:.85rem;
  }
  .aa-card--lead .aa-card__meta{
    margin-top:1.35rem;
    padding-top:0;
  }
}

/* A rule under the lead separates the headline post from the run of the
   archive without a heading having to say so. */
@media (min-width:700px){
  .aa-card--lead::after{
    content:"";
    position:absolute;
    left:0;
    right:0;
    bottom:calc(clamp(28px,3.4vw,40px) / -2);
    border-bottom:1px solid var(--line);
  }
}


/* -- Article -------------------------------------------------------------- */

.aa-article__head{padding-top:clamp(8px,2vw,20px)}

/* Same trick as the card title: padding for the touch target, negative margin
   so the type does not move for it. */
.aa-article__kicker a{
  display:inline-block;
  padding-block:.8rem;
  margin-block:-.8rem;
  text-decoration:none;
}
.aa-article__kicker a:hover{
  text-decoration:underline;
  text-underline-offset:.25em;
}

.aa-article__meta{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:.5rem;
  margin:1.4rem 0 0;
  color:var(--grey);
  font-size:.875rem;
}

.aa-article__hero{
  width:min(980px,100%);
  margin:clamp(32px,5vw,52px) auto clamp(36px,5vw,56px);
}
.aa-article__hero img{
  width:100%;
  height:100%;
  aspect-ratio:16/9;
  object-fit:cover;
  border-radius:var(--radius);
  background:var(--surface);
}
.aa-article__caption{
  margin:.85rem 0 0;
  color:var(--grey);
  font-size:.8125rem;
  line-height:1.5;
}


/* -- Contents -------------------------------------------------------------
   Shown only when a post has three sections or more. Below that it is
   furniture that pushes the first paragraph off a phone screen. */

.aa-toc{
  margin-bottom:clamp(32px,4vw,44px);
  padding:1.1rem 1.5rem 1.25rem;
  background:var(--surface);
  border-radius:var(--radius-sm);
}
.aa-toc__label{
  margin:0 0 .35rem;
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--grey);
}
.aa-toc__list{list-style:none}
.aa-toc__item a{
  display:flex;
  align-items:center;
  min-height:44px;
  padding-block:.3rem;
  color:var(--ink);
  font-size:.9375rem;
  line-height:1.4;
  text-decoration:none;
}
.aa-toc__item a:hover{color:var(--red)}
.aa-toc__item--sub{padding-left:1.15rem}
.aa-toc__item--sub a{
  color:var(--grey);
  font-size:.875rem;
}


/* -- Prose, the article's share ------------------------------------------
   pages.css sets the measure, the headings, the lists and the tables. These
   are the four things an article needs on top of that. */

/* Longer than a page's copy, so a step up in size and air. 18px against the
   68ch column lands the measure at roughly 71 characters — a page's 17px puts
   77 on the same line, which is past the point where the eye starts losing
   the return. */
.aa-article__body .aa-prose{
  font-size:1.125rem;
  line-height:1.75;
  overflow-wrap:break-word;
}

/* Landing from the contents list should not put the heading against the top
   edge of the viewport. */
.aa-article__body .aa-prose :is(h2,h3,h4){scroll-margin-top:1.75rem}

/* System monospace. A code face would be a second web font for a handful of
   inline spans, which is not a trade this site makes. */
.aa-prose code,
.aa-prose kbd,
.aa-prose samp{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;
  font-size:.9em;
}
.aa-prose :not(pre) > code{
  padding:.15em .4em;
  border-radius:6px;
  background:var(--surface);
  color:var(--ink);
}
.aa-prose pre{
  margin:2rem 0;
  padding:1.25rem 1.4rem;
  border-radius:var(--radius-sm);
  background:var(--ink);
  color:#f2f2f5;
  font-size:.875rem;
  line-height:1.65;
  overflow-x:auto;
  -webkit-overflow-scrolling:touch;
}
.aa-prose pre code{
  padding:0;
  background:none;
  color:inherit;
}

.aa-prose blockquote cite{
  display:block;
  margin-top:.75rem;
  font-size:.875rem;
  font-weight:400;
  font-style:normal;
  color:var(--grey);
}

/* The nine posts predate the block editor. These are its classes. */
.aa-prose .wp-caption{max-width:100%}
.aa-prose .wp-caption-text{
  margin-top:.7rem;
  color:var(--grey);
  font-size:.875rem;
}
.aa-prose .alignleft{float:left;margin:.4rem 1.6rem 1.2rem 0;max-width:50%}
.aa-prose .alignright{float:right;margin:.4rem 0 1.2rem 1.6rem;max-width:50%}
.aa-prose .aligncenter{margin-inline:auto}
@media (max-width:600px){
  .aa-prose .alignleft,
  .aa-prose .alignright{float:none;margin-inline:0;max-width:100%}
}

.aa-pagelinks{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:.5rem;
  margin-top:2.5rem;
  font-size:.875rem;
  color:var(--grey);
}
.aa-pagelinks a{color:var(--ink)}


/* -- Article foot --------------------------------------------------------- */

.aa-article__foot{margin-top:clamp(32px,4vw,44px)}
.aa-article__tags{
  display:flex;
  flex-wrap:wrap;
  gap:.5rem;
  margin:0;
}
.aa-tag{
  display:inline-flex;
  align-items:center;
  min-height:44px;
  padding:0 1rem;
  border:1px solid var(--line);
  border-radius:var(--radius-pill);
  color:var(--grey);
  font-size:.8125rem;
  text-decoration:none;
  transition:border-color .16s ease,color .16s ease;
}
.aa-tag:hover{
  border-color:var(--ink);
  color:var(--ink);
}


/* -- Call to action ------------------------------------------------------- */

.aa-cta{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:1.25rem;
  margin-top:clamp(40px,6vw,64px);
  padding:clamp(24px,4vw,36px);
  background:var(--surface);
  border-radius:var(--radius);
}
.aa-cta__title{
  margin:0 0 .3rem;
  color:var(--ink);
  font-size:1.15rem;
  font-weight:600;
  line-height:1.3;
}
.aa-cta__note{
  margin:0;
  color:var(--grey);
  font-size:.9375rem;
}
.aa-cta .btn{flex:none}

@media (min-width:660px){
  .aa-cta{
    flex-direction:row;
    align-items:center;
    justify-content:space-between;
    gap:2rem;
  }
}


/* -- Previous / next ------------------------------------------------------ */

.aa-postnav{
  display:grid;
  gap:1rem;
  margin-top:clamp(48px,7vw,80px);
  padding-top:clamp(28px,4vw,40px);
  border-top:1px solid var(--line);
}
.aa-postnav__item{
  display:flex;
  flex-direction:column;
  gap:.45rem;
  min-height:44px;
  padding:1.15rem 1.35rem;
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  text-decoration:none;
  transition:border-color .16s ease,background .16s ease;
}
.aa-postnav__item:hover{
  border-color:var(--ink);
  background:var(--surface);
}
.aa-postnav__label{
  color:var(--grey);
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
}
.aa-postnav__title{
  font-weight:600;
  line-height:1.35;
  overflow-wrap:break-word;
}

@media (min-width:760px){
  .aa-postnav{
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:1.25rem;
  }
  .aa-postnav__item--next{
    grid-column:2;
    text-align:right;
    align-items:flex-end;
  }
}


/* -- Related -------------------------------------------------------------- */

.aa-related{margin-top:clamp(56px,8vw,96px)}
.aa-related__title{
  margin-bottom:clamp(24px,3vw,36px);
  font-size:clamp(1.45rem,2.4vw,1.85rem);
}


/* -- Suggestions ---------------------------------------------------------- */

.aa-suggest{
  list-style:none;
  width:min(520px,100%);
  margin:1.75rem 0 0;
}
.aa-suggest a{
  display:flex;
  align-items:center;
  min-height:52px;
  border-bottom:1px solid var(--line);
  color:var(--ink);
  font-weight:500;
  text-decoration:none;
}
.aa-suggest a:hover{color:var(--red)}


/* -- Pagination -----------------------------------------------------------
   the_posts_pagination() ships the nav, its accessible name and the hidden
   heading; this only has to make the numbers touchable. */

.aa-pagination{margin-top:clamp(40px,6vw,64px)}
.aa-pagination .nav-links{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:center;
  gap:.5rem;
}
.aa-pagination .page-numbers{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:44px;
  min-height:44px;
  padding:0 .9rem;
  border:1px solid var(--line);
  border-radius:var(--radius-pill);
  color:var(--ink);
  font-size:.9375rem;
  font-weight:500;
  text-decoration:none;
  transition:border-color .16s ease,background .16s ease;
}
.aa-pagination a.page-numbers:hover{
  border-color:var(--ink);
  background:var(--surface);
}
.aa-pagination .page-numbers.current{
  background:var(--ink);
  border-color:var(--ink);
  color:#fff;
}
.aa-pagination .page-numbers.dots{
  border-color:transparent;
  color:var(--grey);
}


/* ===================================================================
   PORTFOLIO SHOWCASE - grid, filter, project detail
   (was assets/parts/showcase.css)
   =================================================================== */

/*
 * The showcase — archive, term archive and project.
 *
 * Merges into app.css and loads after it, so every colour, radius, shadow and
 * measure below is a token already declared in that file's :root. Nothing here
 * introduces a value of its own.
 *
 * The one thing worth reading twice is the cover frame. See .pcard__media.
 */

/* ====================================================================
 * Hero
 * ================================================================= */

.sc-hero{
  position:relative;
  isolation:isolate;
  padding-block:clamp(48px,7vw,88px) clamp(26px,4vw,44px);
  text-align:center;
}

/* Two soft washes of the brand red, well under the text. The page needs a
   little warmth at the top; it does not need a picture. */
.sc-hero::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:
    radial-gradient(620px 300px at 16% -20%, var(--red-wash), transparent 68%),
    radial-gradient(620px 300px at 84% 6%, var(--red-wash), transparent 68%);
}

.sc-hero__badge{
  display:inline-flex;
  align-items:center;
  gap:.55rem;
  margin:0 0 1.35rem;
  padding:.5rem 1.1rem;
  border:1px solid var(--line);
  border-radius:var(--radius-pill);
  background:var(--red-wash);
  color:var(--red);
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  line-height:1.2;
  text-transform:uppercase;
}
.sc-hero__dot{
  flex:none;
  width:7px;
  height:7px;
  border-radius:50%;
  background:var(--red);
}

.sc-hero__title{
  max-width:19ch;
  margin-inline:auto;
  overflow-wrap:break-word;
}
.sc-accent{color:var(--red)}

.sc-hero__lead{
  max-width:35rem;
  margin:1.15rem auto 0;
}

.sc-hero__count{
  margin:1.35rem 0 0;
  font-size:.875rem;
  color:var(--grey);
}

/* ====================================================================
 * Filters
 *
 * Real links to real term archives. They work with JavaScript switched off,
 * which is the whole reason taxonomy-portfolio_category.php exists; script
 * only makes the same links instant.
 *
 * The bar is printed by the template only when a category would actually
 * narrow the grid down, so it never appears as a single lonely "All" pill.
 * ================================================================= */

.sc-filters{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:.6rem;
  margin-top:1.9rem;
}

.sc-filter{
  display:inline-flex;
  align-items:center;
  gap:.55rem;
  min-height:44px;
  padding:.5rem 1.35rem;
  border:1.5px solid var(--line);
  border-radius:var(--radius-pill);
  background:var(--bg);
  color:var(--grey);
  font-size:.9rem;
  font-weight:500;
  line-height:1.2;
  text-decoration:none;
  transition:color .2s ease,border-color .2s ease,background .2s ease;
}
.sc-filter:hover{color:var(--red);border-color:var(--red)}
.sc-filter.is-active{
  background:var(--red);
  border-color:var(--red);
  color:#fff;
}

.sc-filter__count{
  padding:.25rem .5rem;
  border-radius:var(--radius-pill);
  background:var(--surface);
  color:var(--grey);
  font-size:.7rem;
  font-weight:600;
  line-height:1;
}
.sc-filter.is-active .sc-filter__count{
  background:var(--red-dark);
  color:#fff;
}

/* ====================================================================
 * Grid
 * ================================================================= */

.sc-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,310px),1fr));
  gap:28px;
  margin-top:clamp(28px,4vw,40px);
}

/* Three related projects should sit in three columns, not three of four. */
.sc-grid--three{
  grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));
}

.sc-grid .pcard[hidden]{display:none}

.sc-empty{
  margin:0;
  padding:clamp(48px,8vw,84px) 0;
  color:var(--grey);
  text-align:center;
}
.sc-empty__back{margin:0;text-align:center}

/* ====================================================================
 * Card
 * ================================================================= */

.pcard{
  position:relative;
  overflow:hidden;
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--bg);
  box-shadow:var(--shadow);
  transition:transform .35s cubic-bezier(.2,.8,.25,1),box-shadow .35s ease;
}
.pcard:hover,
.pcard:focus-within{
  transform:translateY(-6px);
  box-shadow:var(--shadow-hover);
}

.pcard__link{
  display:flex;
  flex-direction:column;
  height:100%;
  color:inherit;
  text-decoration:none;
}

/*
 * The cover frame.
 *
 * Every one of the seventy-two covers is a full-page capture of a client's
 * site: between 1:0.9 and 1:5.3 tall, and a different size and format each
 * time. So the frame is fixed at 3:2 — exactly the shape of the registered
 * aa-card crop, so a generated card image lands in it without being cropped a
 * second time — and the image fills it.
 *
 * cover, not contain: contained, a 1:5 capture would sit in a 3:2 box as a
 * finger-wide ribbon with two thirds of the card empty, and the grid would
 * read as broken rather than varied. Covered and anchored to 50% 0, every card
 * shows the top of the site — its masthead and hero, the part a visitor
 * recognises — cropped to a consistent shape. Anchoring matters as much as the
 * fit: centred, a ten-thousand-pixel capture would show a band from the middle
 * of somebody's about page.
 */
.pcard__media{
  position:relative;
  display:block;
  overflow:hidden;
  aspect-ratio:3/2;
  background:var(--surface);
}
.pcard__img{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 0;
  transition:transform .6s cubic-bezier(.2,.8,.25,1);
}
.pcard:hover .pcard__img{transform:scale(1.05)}

.pcard__tag{
  position:absolute;
  top:14px;
  left:14px;
  padding:.35rem .8rem;
  border-radius:var(--radius-pill);
  background:var(--bg);
  box-shadow:var(--shadow);
  color:var(--red);
  font-size:.68rem;
  font-weight:600;
  letter-spacing:.1em;
  line-height:1.4;
  text-transform:uppercase;
}

.pcard__go{
  position:absolute;
  right:14px;
  bottom:14px;
  display:grid;
  place-items:center;
  width:42px;
  height:42px;
  border-radius:50%;
  background:var(--red);
  box-shadow:var(--shadow);
  color:#fff;
  transition:opacity .3s ease,transform .3s ease;
}

/* Revealed on hover where there is a pointer to hover with; always there on a
   touch screen, where it is the only affordance the card has. */
@media (hover:hover){
  .pcard__go{opacity:0;transform:translateY(10px)}
  .pcard:hover .pcard__go,
  .pcard:focus-within .pcard__go{opacity:1;transform:none}
}

.pcard__body{
  display:flex;
  flex:1;
  flex-direction:column;
  align-items:center;
  gap:.3rem;
  padding:1.4rem 1.4rem 1.7rem;
  background:linear-gradient(to top,var(--red-wash),transparent 72%);
  text-align:center;
}
.pcard__title{
  color:var(--ink);
  font-size:1.05rem;
  font-weight:600;
  letter-spacing:-.01em;
  line-height:1.35;
  overflow-wrap:anywhere;
}
.pcard__sub{
  color:var(--grey);
  font-size:.83rem;
  line-height:1.5;
}
.pcard__year{
  margin-top:.2rem;
  color:var(--grey);
  font-size:.7rem;
  font-weight:600;
  letter-spacing:.1em;
}

/* A project with no photograph yet: its initial, quietly. Costs no request. */
.sc-blank{
  display:grid;
  place-items:center;
  width:100%;
  height:100%;
  background:var(--surface);
  color:var(--line);
  font-size:clamp(2.5rem,7vw,4rem);
  font-weight:700;
  line-height:1;
}

/* ====================================================================
 * Project
 * ================================================================= */

.sc-back{
  margin:0;
  padding-top:clamp(24px,4vw,40px);
}
.sc-back__link{
  display:inline-flex;
  align-items:center;
  gap:.5rem;
  min-height:44px;
  padding:.5rem 1.25rem;
  border:1.5px solid var(--line);
  border-radius:var(--radius-pill);
  background:var(--bg);
  color:var(--grey);
  font-size:.9rem;
  font-weight:500;
  text-decoration:none;
  transition:color .2s ease,border-color .2s ease,transform .2s ease;
}
.sc-back__link:hover{
  transform:translateX(-3px);
  border-color:var(--red);
  color:var(--red);
}

.sc-head{
  max-width:44rem;
  margin-top:clamp(22px,3vw,34px);
}
.sc-head .t-eyebrow{margin-bottom:.6rem}
/*
 * A shade smaller than .t-h2 at the narrow end, and no smaller anywhere else.
 * The titles are domains — one long word — and at .t-h2's 1.9rem a phone
 * cannot fit "Besshomerenovationltd." before the break opportunity after the
 * dot, so it snaps mid-word instead. Dropping the floor lets the name come
 * apart where its owner would put the join. anywhere stays as the backstop.
 */
.sc-head__title{
  font-size:clamp(1.45rem,4.2vw,3rem);
  overflow-wrap:anywhere;
}
.sc-head__lead{margin:.9rem 0 0}

.sc-hero-img{
  overflow:hidden;
  aspect-ratio:16/9;
  margin-top:clamp(26px,4vw,40px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--surface);
  box-shadow:var(--shadow);
}
.sc-hero-img__img{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 0;
}

/* The meta row. Each pair is printed only if it holds something, so on a
   project that has nothing filled in yet the row collapses to the address of
   the live site — and if even that is missing, to nothing at all. */
.sc-facts{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between;
  gap:1.4rem 2rem;
  margin-top:clamp(24px,3.5vw,36px);
  padding:clamp(20px,3vw,28px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:linear-gradient(to top,var(--red-wash),transparent 65%);
}
.sc-facts__list{
  display:grid;
  flex:1 1 20rem;
  gap:1.2rem 2.5rem;
  grid-template-columns:repeat(auto-fit,minmax(9rem,max-content));
  margin:0;
}
.sc-fact{min-width:0}
.sc-fact__key{
  margin:0;
  color:var(--grey);
  font-size:.7rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
}
.sc-fact__val{
  margin:.3rem 0 0;
  color:var(--ink);
  font-size:.98rem;
  font-weight:500;
  overflow-wrap:anywhere;
}
.sc-facts__go{
  flex:0 0 auto;
  margin:0;
}

.sc-body{
  max-width:44rem;
  margin-top:clamp(34px,5vw,56px);
  color:var(--ink-soft);
}
.sc-body > :first-child{margin-top:0}
.sc-body h2{margin:2rem 0 .6rem;font-size:1.3rem}
.sc-body h3{margin:1.6rem 0 .5rem;font-size:1.08rem}
.sc-body p{margin:0 0 1.1em}
.sc-body ul,.sc-body ol{margin:0 0 1.1em;padding-left:1.25rem}
.sc-body li{margin-bottom:.35rem}
.sc-body img{border-radius:var(--radius-sm)}
.sc-body a{color:var(--red);text-decoration:underline;text-underline-offset:3px}

.sc-section-title{margin-bottom:1rem}
.sc-gallery,
.sc-video{margin-top:clamp(38px,6vw,64px)}

.sc-gallery__grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,220px),1fr));
  gap:16px;
}
.sc-shot{
  display:block;
  overflow:hidden;
  aspect-ratio:3/2;
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  background:var(--surface);
}
.sc-shot__img{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 0;
  transition:transform .35s ease;
}
.sc-shot:hover .sc-shot__img{transform:scale(1.04)}

/* Built by showcase.js on the first click, never before. Without script the
   thumbnails are links to the full image and behave like links. */
.sc-lightbox{
  position:fixed;
  inset:0;
  z-index:100;
  display:grid;
  place-items:center;
  padding:clamp(16px,4vw,40px);
  background:rgba(17,17,20,.92); /* --ink at 92%; no token carries it with alpha. */
  opacity:0;
  pointer-events:none;
  transition:opacity .25s ease;
}
.sc-lightbox.is-open{opacity:1;pointer-events:auto}
.sc-lightbox__img{
  max-width:100%;
  max-height:88vh;
  width:auto;
  border-radius:var(--radius-sm);
}
.sc-lightbox__close{
  position:absolute;
  top:clamp(12px,2vw,22px);
  right:clamp(12px,2vw,22px);
  display:grid;
  place-items:center;
  width:46px;
  height:46px;
  padding:0;
  border:0;
  border-radius:50%;
  background:var(--surface);
  color:var(--ink);
  cursor:pointer;
}

.sc-video__player,
.sc-video__frame{
  width:100%;
  aspect-ratio:16/9;
  border:0;
  border-radius:var(--radius);
  background:var(--ink);
  box-shadow:var(--shadow);
}

/* No iframe, no third-party connection and no player until somebody asks for
   one. Without script this is a link to the video; with it, showcase.js swaps
   the real embed in on click. */
.sc-video__facade{
  position:relative;
  display:block;
  overflow:hidden;
  aspect-ratio:16/9;
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--surface);
  box-shadow:var(--shadow);
}
.sc-video__poster{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 0;
}
.sc-video__play{
  position:absolute;
  inset:0;
  display:grid;
  place-items:center;
  width:74px;
  height:74px;
  margin:auto;
  padding-left:4px;
  border-radius:50%;
  background:var(--red);
  box-shadow:var(--shadow-hover);
  color:#fff;
  transition:transform .25s ease;
}
.sc-video__facade:hover .sc-video__play{transform:scale(1.07)}

/* ====================================================================
 * Related and call to action
 * ================================================================= */

.sc-related{padding-top:clamp(50px,7vw,84px)}
.sc-related__head{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  justify-content:space-between;
  gap:.5rem 1.5rem;
}
.sc-related__all{
  display:inline-flex;
  align-items:center;
  gap:.45rem;
  min-height:44px;
  color:var(--red);
  font-size:.9rem;
  font-weight:600;
  text-decoration:none;
}
.sc-related__all:hover .sc-arrow{transform:translateX(3px)}
.sc-arrow{flex:none;transition:transform .2s ease}
.btn:hover .sc-arrow{transform:translateX(3px)}

.sc-cta{
  margin-top:clamp(56px,8vw,96px);
  text-align:center;
}
.sc-cta .t-h2{margin-top:.45rem}
.sc-cta .t-lead{max-width:35rem;margin:1rem auto 0}
.sc-cta__actions{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:.8rem;
  margin:1.9rem 0 0;
}

/* ====================================================================
 * Narrow
 * ================================================================= */

@media (max-width:560px){
  .sc-grid{gap:20px}
  .sc-gallery__grid{grid-template-columns:repeat(2,1fr);gap:10px}
  .sc-facts__go .btn{width:100%}
}


/* ===================================================================
   CONTACT CHANNELS - email, phone, WhatsApp
   (was assets/parts/contact.css)
   =================================================================== */

/*
 * Contact — email, phone and WhatsApp as three links.
 *
 * Merges into app.css and loads after it. Every colour, radius and measure
 * below comes from the tokens already declared in app.css :root; nothing here
 * declares a new one.
 *
 * The whole block is three anchors. They are drawn as cards rather than as a
 * line of text because on a phone — where most of these are tapped — a target
 * has to be findable with a thumb, and a 15px mailto: in a paragraph is not.
 * Nothing animates on load, nothing floats over the page, and there is no
 * fourth thing competing with them.
 */

.aa-cblock{
  margin-block:clamp(24px,3vw,40px);
}
.aa-cblock__title{margin-bottom:.5rem}
.aa-cblock__intro{
  max-width:52ch;
  margin-bottom:1.5rem;
  color:var(--grey);
}

/* One column on a phone, side by side once there is room for three without
   the value wrapping. auto-fit rather than a fixed count, so a site with only
   two channels filled in gets two full-width cards instead of a gap. */
.aa-cblock__list{
  display:grid;
  gap:.75rem;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  list-style:none;
}

/* ---- The link --------------------------------------------------------
   min-height is the tap target, and it is on the anchor rather than on an
   inner span so the whole card is the target rather than the words in it. */

.aa-cblock__link{
  display:flex;
  align-items:center;
  gap:.9rem;
  min-height:64px;
  height:100%;
  padding:.85rem 1.1rem;
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--bg);
  color:var(--ink);
  text-decoration:none;
  transition:border-color .16s ease,background .16s ease;
}
.aa-cblock__link:hover{
  border-color:var(--red);
  background:var(--surface);
}

/* The global focus ring rounds itself to 4px, which on a 22px card leaves the
   outline cutting across the corners. */
.aa-cblock__link:focus-visible{
  outline:2px solid var(--red);
  outline-offset:3px;
  border-radius:var(--radius);
}

/* ---- The mark --------------------------------------------------------
   44px square in its own right, so it is a target on its own even where the
   card is not — and the one place the red appears in the block. */

.aa-cblock__icon{
  display:grid;
  place-items:center;
  flex:0 0 auto;
  width:44px;
  height:44px;
  border-radius:var(--radius);
  background:var(--surface);
  color:var(--red);
}
.aa-cblock__link:hover .aa-cblock__icon{
  background:var(--red);
  color:#fff;
}
.aa-cblock__glyph{width:21px;height:21px}

/* ---- The words -------------------------------------------------------
   Label above value: "Email" is what the reader is looking for, the address
   is what they read once they have found it. min-width:0 lets a long address
   shrink inside the grid track rather than pushing the card wider than it. */

.aa-cblock__text{
  display:flex;
  flex-direction:column;
  min-width:0;
}
.aa-cblock__label{
  font-size:.75rem;
  font-weight:600;
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--grey);
  line-height:1.4;
}
.aa-cblock__value{
  font-weight:500;
  line-height:1.35;
  /* An email address has no spaces to break at, so it is allowed to break
     anywhere rather than widening the card past its column. */
  overflow-wrap:anywhere;
}
.aa-cblock__link:hover .aa-cblock__value{color:var(--red-dark)}

/* ---- On a page's copy ------------------------------------------------
   The block is usually dropped into post_content by the shortcode, where
   .aa-prose caps its children at a reading measure. A row of cards is not
   prose and wants the whole column. */

.aa-prose > .aa-cblock{max-width:none}


/* ===================================================================
   LOGO + HEADER HEIGHT
   (was assets/parts/logo.css)
   =================================================================== */

/*
 * The brand mark, and the room the sticky bar above it owes everything else.
 *
 * Merges into app.css and loads after it. No colour, radius or measure below
 * is new: they all come from the tokens already declared in app.css :root.
 *
 * Two custom properties are declared here, and neither is a design token. They
 * are measurements — the height of the header bar, and the height of the
 * header — and they exist so that the bar and the things which have to clear
 * it are one number rather than two that drift apart at the next breakpoint.
 *
 * The mark shipped for this is 218x96 and trimmed to its ink — the .svg it
 * replaces carried ten transparent pixels on every side, a tenth of its height
 * spent on nothing — which is twice the 48px it is drawn at, and so sharp on a
 * 2x screen.
 */

/* ---- Clearing the header ----------------------------------------------
 *
 * .site-header is position:sticky, so at rest it occupies its own space in the
 * flow and covers nothing; #content starts exactly where the header ends. What
 * it does cover is anything scrolled to the top of the viewport, because
 * scroll-padding-top on the scrollport was never set — it defaults to `auto`,
 * which resolves to zero. Every in-page link therefore parks its target at
 * y=0, under 63 to 75 pixels of header: the theme's own "Skip to content" link
 * puts the hero's first lines behind the bar, and the table of contents on a
 * post does the same to the heading it was pointing at. That is the overlap.
 *
 * The offset is not guessed. --aa-header-bar is where the bar's height is
 * declared, once; the min-height below is the only rule that reads it as a
 * height, and everything which has to clear the bar reads it through
 * --aa-header-h, which adds the hairline rule beneath it. The two therefore
 * cannot disagree — at the breakpoint, changing the one value moves the bar
 * and the offset together.
 *
 * app.js then overwrites --aa-header-h on the root element with the height it
 * measures, which keeps this honest if the header ever comes out taller than
 * the design assumed: a translated call to action wrapping, an admin bar, a
 * mark deeper than the one shipped here. Nothing depends on that measurement
 * arriving — the declared value below is already correct — and the property is
 * only ever used for scroll positioning, which is settled at the moment of a
 * jump rather than at layout, so a late correction cannot shift the page.
 */
:root{
  --aa-header-bar:74px;
  --aa-header-h:calc(var(--aa-header-bar) + 1px); /* + the rule under the bar */
}
@media (max-width:1023.98px){
  :root{--aa-header-bar:62px}
}

.site-header__inner{min-height:var(--aa-header-bar)}

/* A little air under the bar, so an anchored heading reads as the top of
   something rather than as a line jammed against a border. */
html{scroll-padding-top:calc(var(--aa-header-h) + 1rem)}

/* The article headings carry their own 1.75rem of scroll-margin, from before
   the scrollport knew about the header. It stacks on top of the padding above,
   which would leave an anchored heading in a post sitting 28px lower than the
   same heading anywhere else on the site. One offset, in one place. */
.aa-article__body .aa-prose :is(h2,h3,h4){scroll-margin-top:0}

/* ---- The mark ----------------------------------------------------------
 *
 * The logo is served as a pair — a WebP for the browsers that take it, the PNG
 * for the rest — so the <img> the theme already styles now arrives inside a
 * <picture>. That element is inline by default, which under a non-flex parent
 * hangs the descender space of a line box beneath the mark; blockifying it
 * costs nothing and closes the gap in the footer, where the brand is not a
 * flex row. The <img> carries its own width and height either way, so the box
 * is reserved from the markup and neither source can shift the header under it.
 */
.site-brand picture,
.site-footer__brand picture{display:block;max-width:100%}

/* The heights app.css set were cut for the text wordmark that used to stand
   here. The lockup is stacked — wings, wordmark, strapline — so 40px of it
   leaves a wordmark shorter than the navigation beside it, and a brand that
   reads as smaller than the menu is not a brand mark. 48px puts the wordmark
   level with the nav and still leaves 13px of air top and bottom inside the
   74px bar; below 1024px the bar is 62px and the mark is 38px, the same
   proportion and the same height the footer already uses. */
.site-brand .custom-logo{width:auto;height:48px}
@media (max-width:1023.98px){
  .site-brand .custom-logo{height:38px}
}


/* ===================================================================
   OUR TEAM
   (was assets/parts/team.css)
   =================================================================== */

/* ---- 6. Team ----------------------------------------------------------
   A dark band between the white sections above it and the footer below, and
   the only place on the site where colour is used decoratively. Five flat
   panels, five cut-outs standing in them, and the job title — not the name —
   set as the loud line.

   Everything here reads its greys, shape and measure from the tokens at the
   top of this stylesheet. The six colours below are the exception: they are
   this section's own material and belong to nothing else on the site, so
   they are declared on .hp-team rather than on :root.

   The five panel tones are all light enough to carry --ink at AA:
     t1 sky        #57B6EF   8.39:1
     t2 warm grey  #D0C3AC  10.85:1
     t3 ice        #A5CDE3  11.17:1
     t4 coral      #FF9481   8.80:1
     t5 periwinkle #9DA6F2   8.23:1
   The name is the same ink at 72%, which is the worst case on this page and
   still clears AA on every panel (4.79:1 on t5, 6.63:1 on t3). */

.hp-team{
  /* The ground was a deep navy when this matched the old site's dark band.
     The owner asked for it to sit on the same grey as the plans section, so
     the panels now carry all the colour and the section reads as part of the
     page rather than a slab dropped into it. The five panel colours were
     always chosen against --ink text, not against the ground, so none of the
     contrast figures above change. */
  --ground:var(--surface);
  --t1:#57B6EF;
  --t2:#D0C3AC;
  --t3:#A5CDE3;
  --t4:#FF9481;
  --t5:#9DA6F2;
  --card:var(--t1);
  --card-radius:16px;
  --card-pad:clamp(14px,1.5vw,20px);

  background:var(--ground);
  color:var(--ink);
}

.hp-team__title{
  text-align:center;
  color:var(--ink);
  font-weight:700;
}

/* Five across, then three, then two. Never one: five full-width portrait
   cards stacked is most of a phone screen each and the row stops reading as
   a group at all. */
.hp-team__row{
  list-style:none;
  margin-top:clamp(38px,5.2vw,72px);
  display:grid;
  gap:clamp(10px,1.1vw,14px);
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:600px){
  .hp-team__row{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (min-width:1000px){
  .hp-team__row{grid-template-columns:repeat(5,minmax(0,1fr))}
}

/* No height is written down anywhere. The card is a column: the two lines of
   text take what they need, the photo well's own ratio takes the rest, and
   the two together land the card at roughly 3:4 — measured 0.72:1 at 1440px
   and 0.75:1 at 360px. A two-line name makes the card taller rather than
   running under the picture, and the grid stretches its neighbours to match,
   so the five figures stay on one baseline either way. */
.hp-face{
  display:flex;
  flex-direction:column;
  padding-top:var(--card-pad);
  background:var(--card);
  color:var(--ink);
  border-radius:var(--card-radius);
  overflow:hidden;
  /* A grid item's automatic minimum is its longest unbreakable word. Without
     this, one long job title — sq: "Bashkethemelues" — pushes the card wider
     than its track and out through the side of the grid. */
  min-width:0;
}

.hp-face--t1{--card:var(--t1)}
.hp-face--t2{--card:var(--t2)}
.hp-face--t3{--card:var(--t3)}
.hp-face--t4{--card:var(--t4)}
.hp-face--t5{--card:var(--t5)}

.hp-face__name{
  display:block;
  padding-inline:var(--card-pad);
  font-size:.8125rem;
  font-weight:400;
  line-height:1.35;
  overflow-wrap:break-word;
  opacity:.72;
}
.hp-face__role{
  display:block;
  padding-inline:var(--card-pad);
  margin-top:.1rem;
  font-size:clamp(1.05rem,1.55vw,1.4rem);
  font-weight:700;
  line-height:1.14;
  letter-spacing:-.02em;
  text-wrap:balance;
  /* Titles are compound words in Albanian and the card is 220px wide at its
     widest. Break inside a word rather than clip it. */
  overflow-wrap:break-word;
}

/* The well's own ratio is the flex-basis, and flex-grow lets it absorb
   whatever a taller neighbour adds to the row. 1:1.04 rather than the
   photographs' own 10:11, because two lines of text on top of a 10:11 well
   makes a card nearer 2:3 than 3:4; the four per cent it costs the figure is
   invisible on a cut-out, which has no edge to show it. */
.hp-face__photo{
  position:relative;
  flex:1 1 auto;
  margin-top:clamp(10px,1.1vw,14px);
  aspect-ratio:1/1.04;
}

/* Absolutely positioned, so the photograph's own dimensions never take part
   in sizing the card: the section is laid out identically before and after
   the images arrive, and reserves its space from the first frame. contain
   with a bottom anchor is what stands all five on the card's floor. */
.hp-face__photo img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:contain;
  object-position:center bottom;
}

/* Shown only when an attachment has gone missing — an empty coloured panel
   looks like a bug, an initial looks like a decision. */
.hp-face__mono{
  position:absolute;
  inset:auto 0 4% 0;
  text-align:center;
  font-size:clamp(3rem,7vw,5.5rem);
  font-weight:700;
  line-height:1;
  letter-spacing:-.04em;
  opacity:.16;
}


/* ===================================================================
   LANDING PAGE - inherited-colour and margin corrections
   (was assets/parts/home-fixes.css)
   =================================================================== */

/**
 * Landing page — corrections to the hero and the plans.
 *
 * Loaded after app.css and it declares no tokens of its own: every colour and
 * measure below resolves to something already in :root. The only literals are
 * zeroes.
 *
 * Two of the three fixes here are the same bug wearing different clothes, so
 * they are explained once, at length, at the top of section 1.
 */

/* ---- 1. Colour is stated, never inherited -----------------------------
 *
 * appalbania is deployed inactive and previewed while Vault is still the live
 * theme, which means every plugin on the site is still loaded — including
 * uicore-framework, Vault's engine. It enqueues uicore-global.css on
 * wp_enqueue_scripts at priority 50; this stylesheet goes on at 20. So its
 * rules are always read after ours, and among them is a bare type selector:
 *
 *   h3{ … color:var(--uicore-typography--h3-c) … }
 *
 * with `body{--uicore-typography--h3-c:var(--e-global-color-uicore_headline)}`
 * and `.elementor-kit-7{--e-global-color-uicore_headline:#101828}` — and
 * Elementor puts elementor-kit-7 on <body> on every page of the site.
 *
 * That is why the middle plan's title went dark and its kicker did not.
 * .hp-plan--feature sets color:#fff on the *card*; the kicker, the feature
 * rows and the button each name a colour of their own, so they were unaffected.
 * The title named none — it only ever *inherited* white — and an inherited
 * value loses to any declaration that matches the element itself, whatever the
 * specificity and whatever the source order. So "Creation" rendered #101828 on
 * #111114: a contrast ratio of 1.02:1, which is the smudge the owner saw.
 *
 * The same rule has been landing on every other heading on the page all along.
 * It simply did no visible harm, because #101828 on white is almost exactly
 * --ink on white. It worked by accident, on one ground only.
 *
 * The fix is not to shout the one heading down. It is to give these two
 * sections a colour of their own and hand their headings back to it, at a
 * specificity a bare type selector cannot reach ((0,1,1) against (0,0,1)).
 * That is order-independent, so it holds whether the merged app.css loads
 * before or after uicore-global.css, and it needs no !important.
 */

.hp-hero{color:var(--ink)}

/* :not() keeps this off the dark card, whose own #fff must keep winning. */
.hp-plan:not(.hp-plan--feature){color:var(--ink)}

.hp-hero :is(h1,h2,h3,h4,h5,h6),
.hp-plan :is(h1,h2,h3,h4,h5,h6){color:inherit}

/* ---- 2. Margins are stated too ----------------------------------------
 *
 * Same mechanism, applied to the box model. uicore-global.css carries a
 * normalize block with `h1{font-size:2em;margin:.67em 0}`, which outranks our
 * `h1,h2,h3,h4{margin:0}` on source order alone. .hp-hero__title already names
 * its own margin-top, so only the bottom leaked: .67em of a 70px headline is
 * 47px, where the lead's own 1.4rem asked for 22px. */
.hp-hero__title{margin-bottom:0}

/* ---- 3. The hero is sized by its content ------------------------------
 *
 * Two things held it open under the button.
 *
 * The first is ours: .hp-hero__cta is a <p>, and the base `p{margin:0 0 1em}`
 * gives it a bottom margin it never wanted. It is the last element in the
 * taller column, so that 1em was added to the hero's height at every
 * breakpoint. .hp-hero__lead was given margin-bottom:0 when it was written;
 * the button's paragraph was missed. The plan cards' buttons carry the same
 * stray 1em, which is why they floated 1em above each card's 36px floor
 * instead of sitting on it.
 *
 * The second is the shape of the grid. The promise list is shorter than the
 * text column — three rows against a headline, a lead and a button — and
 * align-items:center split that difference above and below it, parking ~90px
 * of nothing under the last hairline while the button ran on past it. The
 * section's foot was then set by whichever column happened to be longer.
 *
 * Bottom-aligning the two columns puts the last hairline and the button on one
 * floor, so the hero ends where its content ends. It is written as a stretched
 * grid item with its own flex box rather than align-items:end, because that
 * degrades the right way when the promise rows are filtered to a longer list:
 * once the list is the taller column it simply defines the row, and the text
 * column stays at the top instead of being shoved down to meet it. The rows
 * themselves never move relative to each other, so the hairlines stay
 * continuous at any count. Below 900px the grid is a single column and none of
 * this applies. */

.hp-hero__cta,
.hp-plan__cta{margin-bottom:0}

@media (min-width:900px){
  .hp-hero__grid{align-items:stretch}

  .hp-hero__list{
    display:flex;
    flex-direction:column;
    justify-content:flex-end;
  }
}


/* ===================================================================
   INNER PAGES - layout system
   (was assets/parts/pages2.css)
   Overrides earlier rules in the INNER PAGES section; the overridden
   rules are listed as OVERRIDES comments in the block below.
   =================================================================== */

/*
 * Inner pages, second pass — measure, rhythm and the second column.
 *
 * Merges into app.css AFTER the INNER PAGES section it corrects. Every colour,
 * radius, shadow and spacing token below is read from the :root app.css already
 * declares; this file declares no design token of its own. --aa-measure is the
 * one custom property it adds, and that is layout arithmetic — the width of a
 * line of type — rather than a design value.
 *
 * WHAT WAS WRONG
 *
 * `.aa-prose > *{max-width:68ch}` capped every child and left the whole page
 * pinned to the left edge of a 1200px wrap. On a 1440px screen the copy filled
 * about 720px and the remaining 480 were empty — a correct reading measure in
 * the wrong place, which reads as a draft rather than a design. The hero above
 * it was an eyebrow and an h1 and nothing else, because not one of these pages
 * has an excerpt. Below the hero there was no structure at all: headings,
 * paragraphs and a bare <ol>, all the same width and all the same weight, with
 * a blockquote sitting straight under the h1 on the longest page of the lot.
 *
 * WHAT REPLACES IT
 *
 * 1. The measure is a named column in a grid rather than a cap on a child.
 *    .aa-prose is a two-track grid — text | full — so the copy keeps its 68ch
 *    while a row of price cards or a wall of logos runs the width of the wrap.
 *    That is the shape the landing page already uses: .hp-head holds a heading
 *    to 17ch and a lead to 46ch above a grid that fills the page. The copy is
 *    not adrift beside the emptiness any more; it is the left column of
 *    something.
 *
 * 2. A page with nothing wide on it has nothing to align to, so that one is
 *    centred instead (.aa-prose--narrow), and only ever under a centred hero.
 *    page.php decides by looking at the copy.
 *
 * 3. A page with four or more headings gets a second column with something
 *    real in it: a sticky contents list built from the page's own h2s, and on
 *    a service page one button under it.
 *
 * 4. The hero sits on a --surface band with a rule under the title, so it is
 *    finished with nothing but an eyebrow and a heading — which is all any of
 *    these pages gives it.
 *
 * 5. Vertical rhythm is declared once, between siblings, rather than left to
 *    margin collapsing that a grid container does not do anyway.
 *
 * Rules that change something app.css already said are marked OVERRIDES, so
 * they can be folded into the section above when the parts are merged.
 *
 * Everything that touches .aa-prose is written from .aa-page-body. single.php
 * uses .aa-prose as well, for a blog post, and none of this belongs there.
 */

/* ====================================================================
 * The band at the top
 * ================================================================= */

/*
 * OVERRIDES .aa-phero{padding-block:clamp(52px,7vw,96px) 0}
 *
 * The band is the fix for the empty excerpt. Two lines of type on white have
 * no edges and no floor; the same two lines on --surface, closed by the
 * hairline the body then starts from, are a masthead. It also answers the
 * closing panel at the other end of the page, so a page that is only a title
 * and some copy still opens and shuts like a designed thing.
 */
.aa-phero{
  background:var(--surface);
  border-bottom:1px solid var(--line);
  padding-block:clamp(44px,6vw,88px);
}

/* OVERRIDES .aa-page-body--top{border-top:1px solid var(--line)} — page.php no
   longer emits that class, because the band above now draws the line. The rule
   is left harmless rather than removed, in case a template still asks for it. */
.aa-page-body--top{border-top:0}

.aa-page-body{padding-block:clamp(48px,6vw,88px)}

/*
 * OVERRIDES .aa-phero__media{background:var(--surface)} — a --surface panel on
 * a --surface band is invisible. On the band the drawing sits on white, which
 * is the same inversion the cards use.
 */
.aa-phero__media{background:var(--bg)}

/* The mark that closes off a hero with no standfirst under it. Decorative, and
   aria-hidden in the markup. */
.aa-phero__rule{
  display:block;
  width:56px;
  height:4px;
  margin-top:clamp(18px,2vw,26px);
  border-radius:2px;
  background:var(--red);
}
.aa-phero__lead{margin-top:clamp(18px,2vw,26px)}
.aa-phero__meta{margin:1rem 0 0;color:var(--grey)}

/* No drawing, so the title is the only thing on the band and belongs in the
   middle of it rather than against its left edge. */
.aa-phero--center .aa-phero__inner{justify-items:center;text-align:center}
.aa-phero--center .aa-phero__text{margin-inline:auto}
.aa-phero--center .aa-phero__rule{margin-inline:auto}
.aa-phero--center .aa-phero__lead{margin-inline:auto}

/* ====================================================================
 * Two columns, when the page has earned them
 * ================================================================= */

/*
 * The copy keeps its measure and the rail is 280px; the space is the gutter
 * between them rather than a margin outside them, so the copy starts under the
 * hero's title and the rail ends under the hero's drawing. Both edges of the
 * page are accounted for, which is the whole difference between a two-column
 * layout and a column with a gap after it.
 */
.aa-page__cols{--aa-measure:68ch}

/*
 * The rail comes before the copy in the source, and is put back beside it by
 * grid placement rather than by source order. That is not tidiness: a contents
 * list is navigation into the page, and below 1000px there are no columns, so
 * source order is what a reader gets. After the copy it would be a list of
 * links to things they have already scrolled past. Before it, it is what it
 * says it is — and the tab order matches what the eye sees, at every width.
 */
@media (min-width:1000px){
  .aa-page__cols--aside{
    display:grid;
    grid-template-columns:minmax(0,var(--aa-measure)) minmax(220px,280px);
    column-gap:clamp(40px,4vw,64px);
    justify-content:space-between;
    align-items:start;
  }
  .aa-page__cols--aside > .aa-pside{grid-area:1/2}
  .aa-page__cols--aside > .aa-prose{grid-area:1/1}
}

.aa-pside{margin-bottom:clamp(36px,5vw,48px)}

@media (min-width:1000px){
  .aa-pside{
    position:sticky;
    top:calc(var(--aa-header-h) + 1.25rem);
    margin-bottom:0;
  }
}

.aa-pside__panel{
  padding:clamp(20px,2.4vw,26px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--bg);
}
.aa-pside__panel + .aa-pside__panel{margin-top:.9rem}
.aa-pside__title{margin-bottom:.4rem}

/*
 * Not numbered. The two longest pages on the site are a policy and a terms
 * page whose headings already begin "1.", "2.", "3.", and a counter beside
 * them would put two numbers on every row. Hairlines are enough to separate
 * one entry from the next; the red edge is what says which one the pointer is
 * on, and it is drawn in the padding so nothing moves when it appears.
 */
.aa-pside__toc{
  list-style:none;
  margin:0;
  padding:0;
}
.aa-pside__toc li{margin:0}

.aa-pside__toc a{
  position:relative;
  display:flex;
  align-items:center;
  min-height:44px;               /* the tap target, on the anchor itself */
  padding:.5rem 0 .5rem .9rem;
  border-top:1px solid var(--line);
  color:var(--grey);
  font-size:.94rem;
  line-height:1.35;
  text-decoration:none;
  transition:color .16s ease;
}
.aa-pside__toc li:first-child a{border-top:0}
.aa-pside__toc a::before{
  content:"";
  position:absolute;
  left:0;
  top:.55rem;
  bottom:.55rem;
  width:2px;
  border-radius:1px;
  background:var(--red);
  opacity:0;
  transition:opacity .16s ease;
}
.aa-pside__toc a:hover,
.aa-pside__toc a:focus-visible{color:var(--ink)}
.aa-pside__toc a:hover::before,
.aa-pside__toc a:focus-visible::before{opacity:1}

.aa-pside__cta{text-align:center}
.aa-pside__cta .btn{width:100%}

/* ====================================================================
 * The measure, as a grid
 * ================================================================= */

/*
 * OVERRIDES .aa-prose > *{max-width:68ch} and the .aa-prose > .aa-grid,
 * .aa-gallery, .aa-video, figure, hr {max-width:none} exceptions under it, and
 * .aa-prose--doc > *{max-width:66ch}.
 *
 * Same measure, placed rather than capped. Two named columns:
 *
 *   text  — the measure. Everything that is read.
 *   full  — the wrap. A row of price cards, a wall of logos, the 3D viewer:
 *           things that are looked at rather than read, and that a 720px
 *           column makes cramped for no reason.
 *
 * The copy sits at the left edge of the wrap and the objects below it run the
 * width of the page. That is not a compromise, it is the shape every section
 * of the landing page already has — .hp-head holds its heading to 17ch and its
 * lead to 46ch above a grid that fills the wrap — and an inner page that used
 * a different one read as a different site.
 *
 * min(100%,…) is what keeps the measure from overflowing a phone, where the
 * declared 68ch is wider than the screen.
 */
.aa-page-body .aa-prose{
  --aa-measure:68ch;

  display:grid;
  grid-template-columns:
    [full-start text-start] min(100%,var(--aa-measure)) [text-end]
    minmax(0,1fr) [full-end];
}

/*
 * OVERRIDES nothing; this is the other half of the fix.
 *
 * The landing-page shape only works because something wide is holding the
 * page open underneath the copy. A page that is nothing but prose — a policy,
 * a pitch — has no such thing, and a measure pinned to the left of a 1200px
 * wrap with 470px of nothing beside it is exactly what made these pages look
 * unfinished. With nothing to align to, the column is centred instead, and
 * page.php sets this class by looking at whether the copy contains a wide
 * object at all.
 */
.aa-page-body .aa-prose--narrow{
  grid-template-columns:
    [full-start] minmax(0,1fr)
    [text-start] min(100%,var(--aa-measure)) [text-end]
    minmax(0,1fr) [full-end];
}

/* A policy is read straight through, and is set a shade narrower for it. */
.aa-page-body .aa-prose--doc{--aa-measure:66ch}

.aa-page-body .aa-prose > *{grid-column:text;max-width:none}

.aa-page-body .aa-prose > .aa-grid,
.aa-page-body .aa-prose > .aa-gallery,
.aa-page-body .aa-prose > .aa-video,
.aa-page-body .aa-prose > .aa-embed,
.aa-page-body .aa-prose > .aa-cblock,
.aa-page-body .aa-prose > figure{grid-column:full}

/*
 * OVERRIDES .aa-grid > .aa-plan:only-child{max-width:440px}.
 *
 * Five of the ten service pages carry exactly one offer. A grid of one is not
 * a grid: given the width of the page it put a 440px card against the left
 * margin with 750px of nothing beside it, which is the same fault as the copy
 * had, in a card. One offer keeps to the column the copy is in and fills it —
 * a panel the width of the text above it, rather than a tile adrift beside it.
 */
.aa-page-body .aa-prose > .aa-grid:has(> .aa-plan:only-child){grid-column:text}
.aa-page-body .aa-grid > .aa-plan:only-child{max-width:none}

/* At that width the card is wide and short, so what is read and what is done
   sit side by side rather than stacking into a long thin strip. */
@media (min-width:680px){
  /*
   * row-gap is zero and the spacing moves onto the children because the
   * picture below spans more rows than the card has: every unused row still
   * pays the gap, and a dozen of them left 160px of nothing under the card.
   */
  .aa-page-body .aa-grid > .aa-plan:only-child{
    display:grid;
    grid-template-columns:minmax(0,1fr) auto;
    align-items:start;
    align-content:start;
    column-gap:clamp(24px,4vw,48px);
    row-gap:0;
  }
  .aa-page-body .aa-grid > .aa-plan:only-child > *{grid-column:1}
  .aa-page-body .aa-grid > .aa-plan:only-child > * + *{margin-top:.85rem}
  .aa-page-body .aa-grid > .aa-plan:only-child > p:last-child{
    grid-column:2;
    grid-row:1/-1;
    align-self:center;
    margin-top:0;
    padding-top:0;
  }

  /* Six ticks down the left of a card this wide is a thin ribbon of text with
     a hole beside it. Two columns is the same list at half the height. */
  .aa-page-body .aa-grid > .aa-plan:only-child > ul{
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(170px,1fr));
    column-gap:1.5rem;
  }

  /* A card that carries a photograph of the thing being sold — the review
     card, not a QR code, which is small by design — puts it in the second
     column and lets the ask sit under the copy. The picture is the reason the
     card is that wide; it should not be stacked under a price and leave the
     right half of the card empty. */
  .aa-page-body .aa-grid > .aa-plan:only-child:has(> figure:not(.aa-qr)){
    grid-template-columns:minmax(0,1fr) minmax(0,300px);
  }
  .aa-page-body .aa-grid > .aa-plan:only-child > figure:not(.aa-qr){
    grid-column:2;
    grid-row:1/span 12;
    align-self:start;
    margin-top:0;
  }
  .aa-page-body .aa-grid > .aa-plan:only-child:has(> figure:not(.aa-qr)) > p:last-child{
    grid-column:1;
    grid-row:auto;
    justify-self:start;
    margin-top:1rem;
  }
}

/* A picture inside a card that wide would be a banner. */
.aa-page-body .aa-grid > .aa-plan:only-child > figure:not(.aa-qr) img{max-width:320px}

/* ---- Rhythm ----------------------------------------------------------
   Grid items do not collapse their margins, so the old em margins on both
   sides of every element would stack: a paragraph's 1.15em under a heading's
   1.9em, every time. Spacing is declared once, between siblings, which is also
   the only way to give a heading more air above it than below without counting
   on collapse to throw one of the two away.

   OVERRIDES the outer margins on .aa-prose h2/h3/h4/p/ul/ol/li/figure/
   blockquote/hr/table and on .aa-grid, ul.aa-gallery, .aa-embed, .aa-video and
   .aa-cblock — all of which were written for a flow container.

   Every rule below is written from .aa-page-body rather than from .aa-prose,
   which is not decoration: app.css sets those margins as `.aa-prose p`,
   `.aa-prose h2` and `ul.aa-gallery`, and a rule written as `.aa-prose > *`
   loses to all three on specificity. One extra ancestor puts the whole system
   above them, and .aa-page-body is the wrapper page.php already draws. When
   these parts are merged the old margins can simply be deleted and the
   ancestor dropped with them. */

.aa-page-body .aa-prose > *{margin-block:0}
.aa-page-body .aa-prose > * + *{margin-top:1.15em}

.aa-page-body .aa-prose > * + h2{margin-top:1.7em}
.aa-page-body .aa-prose > * + h3{margin-top:1.9em}
.aa-page-body .aa-prose > * + h4{margin-top:2em}
.aa-page-body .aa-prose > h2 + *{margin-top:.95rem}
.aa-page-body .aa-prose > h3 + *{margin-top:.75rem}
.aa-page-body .aa-prose > h4 + *{margin-top:.6rem}
.aa-page-body .aa-prose > h2 + h3,
.aa-page-body .aa-prose > h3 + h4{margin-top:1.1em}

.aa-page-body .aa-prose > * + ul,
.aa-page-body .aa-prose > * + ol{margin-top:1.3em}

.aa-page-body .aa-prose > * + .aa-grid,
.aa-page-body .aa-prose > * + .aa-gallery,
.aa-page-body .aa-prose > * + .aa-video,
.aa-page-body .aa-prose > * + .aa-embed,
.aa-page-body .aa-prose > * + .aa-cblock,
.aa-page-body .aa-prose > * + figure,
.aa-page-body .aa-prose > .aa-grid + *,
.aa-page-body .aa-prose > .aa-gallery + *,
.aa-page-body .aa-prose > .aa-video + *,
.aa-page-body .aa-prose > .aa-embed + *,
.aa-page-body .aa-prose > .aa-cblock + *,
.aa-page-body .aa-prose > figure + *{margin-top:clamp(30px,4vw,56px)}

.aa-page-body .aa-prose > * + blockquote,
.aa-page-body .aa-prose > blockquote + *{margin-top:clamp(28px,3.5vw,44px)}

.aa-page-body .aa-prose > * + hr,
.aa-page-body .aa-prose > hr + *{margin-top:clamp(34px,4.5vw,56px)}

.aa-page-body .aa-prose > :first-child{margin-top:0}
.aa-page-body .aa-prose > :last-child{margin-bottom:0}

/* ---- Headings --------------------------------------------------------
   A short red rule over every h2. On a policy with nine sections it is what
   lets a reader find the section they came for without reading the page; on a
   service page it is the only structure between the hero and the cards. */

.aa-page-body .aa-prose > h2::before{
  content:"";
  display:block;
  width:30px;
  height:3px;
  margin-bottom:14px;
  border-radius:2px;
  background:var(--red);
}

/* An h2 that has just been jumped to should land under the header, not behind
   it. The offset is the one the rest of the site already uses. */
.aa-page-body .aa-prose h2{scroll-margin-top:calc(var(--aa-header-h) + 1rem)}

/* ====================================================================
 * Lists
 * ================================================================= */

/*
 * OVERRIDES .aa-prose ul{list-style:disc;padding-left:1.35em} for the top level
 * only — a nested list inside a step or a card keeps the disc it had.
 *
 * A dot the size of a dot, in the one accent colour, aligned to the first line
 * rather than hanging in the gutter of an indent nobody asked for.
 */
.aa-page-body .aa-prose > ul:not(.aa-gallery){
  list-style:none;
  padding-left:0;
  display:grid;
  gap:.6rem;
}
.aa-page-body .aa-prose > ul:not(.aa-gallery) > li{
  position:relative;
  margin:0;
  padding-left:1.75rem;
}
.aa-page-body .aa-prose > ul:not(.aa-gallery) > li::before{
  content:"";
  position:absolute;
  left:.2rem;
  top:.62em;
  width:7px;
  height:7px;
  border-radius:50%;
  background:var(--red);
}
.aa-page-body .aa-prose > ul:not(.aa-gallery) > li > ul,
.aa-page-body .aa-prose > ul:not(.aa-gallery) > li > ol{margin-top:.5rem}

/*
 * OVERRIDES .aa-prose ul{list-style:disc;padding-left:1.35em} and
 * .aa-prose li{margin-bottom:.45em} where the contact block is inside the copy.
 *
 * A bug rather than a taste: .aa-cblock__list declares list-style:none, but
 * .aa-prose ul is a class and a type and out-specifies it, so on the one page
 * where the block is dropped into post_content — the contact page, via
 * [aa_contact] — each of the three cards had a disc hanging in the margin
 * beside it. The block owns its own list; the prose rules have no business in
 * it at all.
 */
.aa-prose .aa-cblock ul{list-style:none;margin:0;padding:0}
.aa-prose .aa-cblock li{margin:0}
.aa-prose .aa-cblock li::before{content:none}

/* ---- Numbered lists, as steps ---------------------------------------
   OVERRIDES .aa-prose ol{list-style:decimal;padding-left:1.35em} at the top
   level.

   The partnership page is two ordered lists — four things the studio provides
   and three things the reader does — set as a bare <ol> with a red numeral in
   the margin. They are the substance of the page and they were the least
   visible thing on it. A numeral in a disc gives them a place; an entry with
   real paragraphs inside it gets the card it was always describing, and one
   that is a single line stays a single line, so the two lists still read as
   different kinds of list. */

.aa-page-body .aa-prose > ol{
  list-style:none;
  padding-left:0;
  counter-reset:aa-step;
  display:grid;
  gap:.85rem;
}
.aa-page-body .aa-prose > ol > li{
  counter-increment:aa-step;
  position:relative;
  margin:0;
  padding-left:3.3rem;
  min-height:2.4rem;
}
.aa-page-body .aa-prose > ol > li::marker{content:none}
.aa-page-body .aa-prose > ol > li::before{
  content:counter(aa-step);
  position:absolute;
  left:0;
  top:-.15em;
  display:grid;
  place-items:center;
  width:2.4rem;
  height:2.4rem;
  border-radius:var(--radius-pill);
  background:var(--red-wash);
  color:var(--red);
  font-size:.95rem;
  font-weight:700;
  font-variant-numeric:tabular-nums;
}

/* An entry with paragraphs in it is a section, not a bullet. */
.aa-page-body .aa-prose > ol > li:has(p){
  padding:clamp(20px,2.4vw,26px) clamp(22px,2.6vw,30px) clamp(20px,2.4vw,26px) 4.4rem;
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:var(--bg);
}
.aa-page-body .aa-prose > ol > li:has(p)::before{
  left:clamp(22px,2.6vw,30px);
  top:clamp(20px,2.4vw,26px);
}
.aa-page-body .aa-prose > ol > li > p{margin:0 0 .7em}
.aa-page-body .aa-prose > ol > li > p:last-child{margin-bottom:0}
.aa-page-body .aa-prose > ol > li > p:first-child{
  color:var(--ink);
  font-weight:600;
  font-size:1.05rem;
  line-height:1.4;
}
.aa-page-body .aa-prose > ol > li > ul{margin:.7rem 0 0}

@media (max-width:520px){
  .aa-page-body .aa-prose > ol > li:has(p){
    padding-left:clamp(22px,2.6vw,30px);
    padding-top:4.2rem;
  }
  .aa-page-body .aa-prose > ol > li:has(p)::before{top:clamp(20px,2.4vw,26px)}
}

/* ====================================================================
 * Quotes
 * ================================================================= */

/*
 * OVERRIDES the whole of .aa-prose blockquote.
 *
 * A 3px left rule is what a quote gets when nobody has decided what a quote is.
 * On the partnership page it also arrived directly under the h1 and read as a
 * stray sentence attached to the title. As a panel on --surface with the mark
 * above it, it is an epigraph: clearly the page speaking about itself before
 * the page starts, and clearly not the first paragraph.
 */
.aa-page-body .aa-prose blockquote{
  padding:clamp(26px,3.2vw,38px) clamp(26px,3.2vw,40px);
  border:0;
  border-radius:var(--radius);
  background:var(--surface);
  color:var(--ink);
  font-size:clamp(1.08rem,1.5vw,1.28rem);
  font-weight:500;
  font-style:normal;
  line-height:1.5;
}
.aa-page-body .aa-prose blockquote::before{
  content:"";
  display:block;
  width:30px;
  height:24px;
  margin-bottom:.75rem;
  background:var(--red);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 24'%3E%3Cpath fill='%23000' d='M0 24V13.4C0 6.4 3.9 1.7 11.6 0l1.5 3.9C8.7 5.3 6.4 7.9 6.2 11.6H12V24H0Zm18 0V13.4C18 6.4 21.9 1.7 29.6 0l1.5 3.9c-4.4 1.4-6.7 4-6.9 7.7H30V24H18Z'/%3E%3C/svg%3E") no-repeat left center/contain;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 24'%3E%3Cpath fill='%23000' d='M0 24V13.4C0 6.4 3.9 1.7 11.6 0l1.5 3.9C8.7 5.3 6.4 7.9 6.2 11.6H12V24H0Zm18 0V13.4C18 6.4 21.9 1.7 29.6 0l1.5 3.9c-4.4 1.4-6.7 4-6.9 7.7H30V24H18Z'/%3E%3C/svg%3E") no-repeat left center/contain;
}
.aa-page-body .aa-prose blockquote p:last-child{margin-bottom:0}

/* ====================================================================
 * The panel that closes a service page
 * ================================================================= */

/* OVERRIDES .aa-close{border-top:1px solid var(--line)} — the panel has its own
   edges now, and a rule above it as well would be two endings. */
.aa-close{border-top:0}

.aa-close__panel{
  padding:clamp(28px,4vw,52px);
  border-radius:var(--radius);
  background:var(--surface);
}
.aa-close__eyebrow{margin-bottom:1.1rem}
.aa-close__panel .aa-cblock{margin-block:0}

/* ====================================================================
 * Small screens
 * ================================================================= */

@media (max-width:560px){
  .aa-phero__text{max-width:none}
  .aa-phero__rule{width:44px;height:3px}
}

/* ---- A body that is only an offer ------------------------------------
   Five of the ten service pages carry one offer and nothing else: no
   heading, no paragraph, just the card. Left-aligned inside the wrap that
   leaves ~475px of white beside it, which is what made these pages read as
   unfinished. There is no prose for a centred card to fall out of step
   with - the card is the whole body - so it is centred on itself. The
   :only-child is doing real work here: the moment a page has copy as well,
   the card goes back to sharing the copy's left edge. */
.aa-page-body .aa-prose > .aa-grid:has(> .aa-plan:only-child):only-child{
  /* Ties on specificity with the rule above that puts a single-plan grid in
     the text track, so it repeats that rule's selector and adds :only-child
     to win outright. justify-self rather than margin:auto, because the
     sibling-rhythm rules set the inline margins explicitly and an auto margin
     there is simply overridden. */
  grid-column:full;
  justify-self:center;
  width:min(100%, 760px);
}

/* ===================================================================
   LANDING PAGE - grid, baselines, team panel
   (was assets/parts/home2.css)
   =================================================================== */

/*
 * Landing page, third pass — the services grid, the team row, and the one
 * heading that was still centred.
 *
 * Merges into app.css AFTER the LANDING PAGE and OUR TEAM sections it
 * corrects. It declares no design token of its own: every colour, radius,
 * measure and rhythm value below resolves to something already in the :root
 * at the top of app.css. --row-gap is the one custom property it adds, and
 * that is layout arithmetic — a gap a flex basis has to subtract — rather
 * than a design value.
 *
 * Rules that change something app.css already said are marked OVERRIDES, so
 * they can be folded into the sections above when the parts are merged.
 *
 * WHAT WAS WRONG
 *
 * 1. The services grid shipped two card widths. Ten cards do not divide into
 *    four columns, so two of them spanned two tracks. That bought rows of
 *    three, three and four, cards of 589px beside cards of 284px, and — since
 *    a grid row is as tall as its tallest card — a 331px "Ready to Go
 *    Systems" holding about 150px of content, with 90px of nothing above its
 *    "Read more". It read as a grid that had run out of cards.
 *
 * 2. Titles in one row sat on different baselines, because three of the ten
 *    wrap onto a second line and the rest do not, and everything under a
 *    two-line title started 26px lower than everything under a one-line one.
 *
 * 3. "Our Team" was the only centred heading on a page of six, and the only
 *    one set at 700 rather than 600. Both were left over from a dark centred
 *    band that no longer exists.
 *
 * 4. Five people never fill a row. Two across gave 2 + 2 + 1, three across
 *    gave 3 + 2, and only five across came out even.
 */

/* ====================================================================
 * 3. Services — ten equal cards
 * ================================================================= */

/*
 * OVERRIDES @media (min-width:1000px){.hp-svc-grid{grid-template-columns:repeat(4,minmax(0,1fr))}}
 *
 * One, two, then five across. Ten divides by all three, so no width leaves a
 * short row and no card has to span anything to hide one. Five 222px cards
 * across a 1200px wrap is a narrower card than the four it replaces, so the
 * padding and the gap come in with it: the card keeps about 174px of content,
 * which is two words of title and four lines of description.
 *
 * .hp-svc--wide is no longer emitted by home-services.php, so the three rules
 * app.css carries for it are dead and can be deleted at merge time.
 */
@media (min-width:1000px){
  .hp-svc-grid{
    grid-template-columns:repeat(5,minmax(0,1fr));
    gap:clamp(12px,1.4vw,20px);
  }
  .hp-svc{padding:clamp(18px,1.7vw,24px)}
}

/*
 * Two lines of title, reserved.
 *
 * h1-h4 carry line-height:1.12 in app.css, so 2.24em is exactly two line
 * boxes of whatever size .t-h3 has resolved to. A one-line title sits at the
 * top of the reserved box, which puts every title in a row on one baseline
 * and — the part that is actually visible — starts every description on one
 * baseline too.
 *
 * min-block-size rather than a height: a title that needs a third line in
 * Albanian gets it, and only its own card grows.
 *
 * Scoped to the five-across band because that is the only band where a title
 * wraps: at two across the cards are 346px and every one of the ten fits on a
 * single line, where a reserved second line would be 26px of void in all ten.
 */
@media (min-width:1000px){
  .hp-svc__title{min-block-size:2.24em}
}

/* ====================================================================
 * 6. Team — a heading like the others, and a row that is always full
 * ================================================================= */

/*
 * OVERRIDES .hp-team__title{text-align:center;font-weight:700}
 *
 * The other five headings on the page are start-aligned and 600. This one was
 * centred and bold because the section was rebuilt from a dark centred
 * design; the ground has been --surface for a while now, and the centring was
 * the last thing still describing a band that is not there. The heading is
 * wrapped in .hp-head in home-team.php, so it also picks up the 17ch measure
 * and the rhythm every other section heading has.
 */
.hp-team__title{
  text-align:start;
  font-weight:600;
}

/*
 * OVERRIDES .hp-team__row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
 * OVERRIDES @media (min-width:600px){.hp-team__row{grid-template-columns:repeat(3,minmax(0,1fr))}}
 * OVERRIDES @media (min-width:1000px){.hp-team__row{grid-template-columns:repeat(5,minmax(0,1fr))}}
 *
 * A row of five cannot be divided by two or by three, so counting columns can
 * only ever move the hole: two across left Dali alone with 170px of empty
 * beside him, three across left the last row holding two of three.
 *
 * The panel changes shape instead of the row changing count. Above 1000px all
 * five fit and the panels stay portrait, which is the section as designed.
 * Below that they turn landscape — name and title on the left, the figure
 * standing at the right — and go two across on a tablet and one across on a
 * phone. One across cannot orphan anything; two across can only orphan a last
 * odd panel, and that one takes the whole row.
 *
 * Flex rather than grid because justify-content:center then costs nothing and
 * covers the headcounts this list is filterable to: six people wrap 5 + 1 with
 * the odd panel centred under the row rather than hanging off its left edge.
 */
.hp-team__row{
  --row-gap:clamp(10px,1.1vw,14px);
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:var(--row-gap);
}
.hp-face{flex:0 0 100%}

@media (min-width:600px){
  .hp-face{flex:0 0 calc((100% - var(--row-gap)) / 2)}
  /* An odd headcount leaves the last panel alone; it takes the row instead.
     A landscape panel is as tall as the figure standing in it, not as tall as
     its own width, so a full-width one is exactly as tall as the pair above. */
  .hp-face:last-child:nth-child(odd){flex-basis:100%}
}

@media (min-width:1000px){
  .hp-face,
  .hp-face:last-child:nth-child(odd){flex:0 0 calc((100% - 4 * var(--row-gap)) / 5)}
}

/*
 * OVERRIDES .hp-face{display:flex;flex-direction:column;padding-top:var(--card-pad)}
 * OVERRIDES .hp-face__photo{flex:1 1 auto;margin-top:clamp(10px,1.1vw,14px);aspect-ratio:1/1.04}
 *
 * The landscape panel. Two text rows in the first column with a 1fr row above
 * and below them, so the pair sits centred however tall the tile is; the well
 * in the second column spanning all four, so the figure runs the full height
 * and stands on the tile's floor exactly as it does in the portrait card.
 *
 * The well is sized from its height, not from the card's width. That is what
 * keeps a full-width tile the same height as a half-width one — without it a
 * 707px tile would be 294px tall against its neighbours' 144px, and solving
 * the orphan would have cost more than it bought. It also means the section
 * reserves its exact height before a photograph has loaded, as before.
 *
 * The name and the title already carry padding-inline, which is what separates
 * them from the figure, so the columns need no gap of their own.
 */
@media (max-width:999.98px){
  .hp-face{
    display:grid;
    grid-template-columns:minmax(0,1fr) auto;
    grid-template-rows:1fr auto auto 1fr;
    column-gap:0;
    padding-top:0;
  }
  .hp-face__name{grid-area:2 / 1;align-self:end}
  .hp-face__role{grid-area:3 / 1;align-self:start}
  .hp-face__photo{
    grid-area:1 / 2 / 5 / 3;
    margin-top:0;
    height:clamp(140px,20vw,180px);
    width:auto;
    aspect-ratio:1/1.04;
  }
}

/* ===================================================================
   SYSTEMS PAGE
   (was assets/parts/systems.css)
   =================================================================== */

/*
 * Systems — the four ready-made products on one page.
 *
 * Merges into app.css and loads after it. Every colour, radius and measure
 * below comes from the tokens already declared in app.css :root; nothing here
 * declares a new one, and nothing here restates a rule .aa-plan already has.
 *
 * The card itself is the shared offer card from pages.css. What this file adds
 * is the three things that are only true of this page: four cards that are
 * link targets, four cards that must line up band for band however long their
 * feature lists are, and a demo link that has to be a tap target rather than a
 * phrase that breaks across two lines.
 */

/* ---- The cards are link targets --------------------------------------
   The footer sends readers to /systems/#car-rental and its three siblings.
   html already carries scroll-padding-top for the sticky header, so the
   landing position is right; what was missing was somewhere to land, and a
   sign that you had. :target is that sign — the card the link named draws
   its border in the accent for as long as the fragment is on the URL. */

.aa-systems .aa-plan{outline-offset:4px}
.aa-systems .aa-plan:target{border-color:var(--red)}

/* ---- Four cards, one set of rows -------------------------------------
   The feature lists run four and five items. With the QR code on the floor of
   the card, the odd item out used to spend that difference as a hole above the
   QR — about 80px of it at 1440, which reads as a mistake rather than as
   breathing room.

   Subgrid fixes it at the source: the cards share the grid's row tracks, so
   the price block, the maintenance line, the feature list, the demo link and
   the QR each start on the same line in all four. The leftover height lands
   inside the feature-list row, under the shorter lists, where it is spacing
   rather than a gap.

   The row gap has to be the gap *inside* a card, because a subgrid uses its
   parent's gutters. That makes it the gap between wrapped rows of cards too —
   1rem against a 16-26px column gap, which is the same measure at the width
   where the cards actually wrap. --aa-sys-rows is written by the template from
   the number of blocks the cards came out with, so the span cannot drift from
   the copy; the class only appears when all four agree. */

.aa-systems .aa-grid{row-gap:1rem}

@supports (grid-template-rows:subgrid){
  .aa-systems--aligned .aa-grid > .aa-plan{
    display:grid;
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:subgrid;
    grid-row:span var(--aa-sys-rows,7);
  }
}

/* Without subgrid — and for cards of unequal length, where row tracks cannot
   be shared — the feature list absorbs the difference instead, which puts the
   demo link and the QR on the same floor by the same reasoning. */
.aa-systems .aa-plan > ul{flex:1 1 auto}

/* ---- The demo link ----------------------------------------------------
   "Visit link to check online demo for more: Mandson Rental" is one sentence
   and one destination, and inline it broke as "Mandson / Rental" in every
   card. The sentence gets its own line, the name stays whole on the next, and
   the link is 44px tall so it can be hit with a thumb — padding on an inline
   box would not have been, because the box is what gets tapped.

   The underline lives on the name rather than on the link, so the external
   mark beside it is not underlined too. */

.aa-systems .aa-sys__demo{color:var(--grey)}
.aa-systems .aa-sys__demotext{display:block}

.aa-systems .aa-sys__demolink{
  display:inline-flex;
  align-items:center;
  gap:.4rem;
  min-height:44px;
  max-width:100%;
  font-weight:600;
  white-space:nowrap;
  text-decoration:none;
}
.aa-systems .aa-sys__demolink > span{
  overflow:hidden;
  text-overflow:ellipsis;
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:.18em;
}
.aa-systems .aa-sys__demolink:hover > span{text-decoration-thickness:2px}
.aa-systems .aa-sys__demoicon{flex:none}

/* The card with no demo says so, in the same slot and the same voice. */
.aa-systems .aa-sys__demo--none{font-style:normal}

/* ---- The QR code ------------------------------------------------------
   112px is what a phone camera needs and what the card has room for. The
   markup asked for 300 and was served 768, so every card downloaded a QR
   nearly seven times wider than it drew — the template now asks WordPress for
   the size it is actually painted at and lets srcset hand a retina screen the
   300px crop.

   Barely rounded: the shared card radius takes a bite out of a QR's quiet zone
   at this size, and a quiet zone is not decoration — it is what makes the code
   readable. */

.aa-systems .aa-sys__qr img{
  width:112px;
  max-width:100%;
  border:1px solid var(--line);
  border-radius:6px;
}

/* No demo to scan: the slot keeps its row so the four cards still line up, and
   holds the one thing left worth offering. Bottom-aligned, so the button sits
   on the same floor as the three QR codes beside it. */
.aa-systems .aa-sys__qr--none{
  display:flex;
  align-items:flex-end;
  padding-top:.4rem;
}
.aa-systems .aa-sys__qr--none .btn{min-height:44px;padding:0 1.25rem}

/* ===================================================================
   PORTFOLIO SHOWCASE - filters, one-result views, gallery, legibility
   (was assets/parts/showcase2.css)
   =================================================================== */

/* ===================================================================
   SHOWCASE, SECOND PASS
   Merges into app.css *after* the PORTFOLIO SHOWCASE block, whose rules
   it corrects. Nothing here declares a token: every colour, radius,
   shadow and measure is one already in app.css :root.
   =================================================================== */

/*
 * What this file is for.
 *
 * The showcase was designed against seventy-two cards and reads beautifully
 * with seventy-two cards. It falls apart with one — a category archive holding
 * a single project put a 381px card at the left edge of a 1200px measure and
 * left 819px of white beside it; the gallery reserved five columns for one
 * picture and left 973px; and a meta row built for four facts held one, with
 * its button eight hundred pixels away on the other side. Everything below is
 * the same design told what it is actually holding.
 *
 * Rules in app.css that this file overrides:
 *
 *   .pcard__sub          font-size, line-height   .83rem was 13.28px
 *   .pcard__tag          font-size, letter-spacing .68rem was 10.88px
 *   .pcard__year         font-size                .7rem was 11.2px
 *   .sc-filter__count    font-size                .7rem was 11.2px
 *   .sc-fact__key        font-size                .7rem was 11.2px
 *   .sc-gallery__grid    grid-template-columns, via [data-shots]
 *   .sc-shot             border-radius, aspect-ratio, via .sc-shot--full
 *
 * Everything else is a new modifier and overrides nothing.
 */

/* ====================================================================
 * 1. Legibility
 *
 * The five smallest things on the site all lived in the showcase, and the
 * two smallest sat on a card: a 13.28px summary and a 10.88px uppercase
 * tag, both of them on the part of the page a visitor reads first and
 * neither of them decoration. Nothing here is below 12px, and the two that
 * carry meaning rather than labelling it are at 15px and above.
 *
 * Sizes only. No colour is touched: red on white is 5.3:1 and grey on white
 * 8.7:1, which were never the problem.
 * ================================================================= */

.pcard__sub{
  font-size:.95rem;   /* 15.2px */
  line-height:1.45;
}
.pcard__tag{
  font-size:.78rem;   /* 12.48px */
  letter-spacing:.08em;
}
.pcard__year{
  font-size:.76rem;   /* 12.16px */
}
.sc-filter__count{
  font-size:.75rem;   /* 12px */
}
.sc-fact__key{
  font-size:.76rem;   /* 12.16px */
}

/* ====================================================================
 * 2. A grid holding one or two cards
 *
 * auto-fill lays three 381px tracks across a 1200px measure whether or not
 * there is anything to put in them, so a category with one project in it
 * rendered as a card and two empty columns. Below three, the grid stops
 * pretending and centres what it has.
 *
 * The --one/--two classes come from archive-portfolio.php; the is-one/is-two
 * classes come from showcase.js when it filters the full grid in the page, so
 * /portfolio-category/system/ and the "System" pill produce the same layout.
 * ================================================================= */

.sc-grid--one,
.sc-grid.is-one,
.sc-grid--two,
.sc-grid.is-two{
  justify-content:center;
  margin-inline:auto;
}

.sc-grid--two,
.sc-grid.is-two{
  grid-template-columns:repeat(2,minmax(0,1fr));
  max-width:800px;
}

.sc-grid--one,
.sc-grid.is-one{
  grid-template-columns:minmax(0,1fr);
  max-width:760px;
}

/*
 * One card, given the room it now has.
 *
 * A single card stretched to 760px and left portrait would be a very tall
 * photograph of somebody's masthead. Turned on its side it is a feature — the
 * cover at the proportions it was cropped for, the name and the summary
 * beside it — and it fills its measure instead of sitting in the corner of it.
 */
@media (min-width:720px){
  .sc-grid--one .pcard__link,
  .sc-grid.is-one .pcard__link{
    flex-direction:row;
    align-items:stretch;
  }

  .sc-grid--one .pcard__media,
  .sc-grid.is-one .pcard__media{
    flex:0 0 58%;
  }

  .sc-grid--one .pcard__body,
  .sc-grid.is-one .pcard__body{
    flex:1 1 auto;
    align-items:flex-start;
    justify-content:center;
    padding:1.6rem 1.7rem;
    /* The wash follows the card: it rose from the foot of a portrait card,
       so on a landscape one it comes in from the outside edge. */
    background:linear-gradient(to left,var(--red-wash),transparent 72%);
    text-align:left;
  }

  .sc-grid--one .pcard__title,
  .sc-grid.is-one .pcard__title{
    font-size:1.25rem;
  }
}

/* ====================================================================
 * 3. The meta row when there is barely any meta
 *
 * space-between is right for four pairs and absurd for one. Under three the
 * box sizes itself to its contents instead of to the measure, so the pair and
 * the button read as one object rather than as two things at opposite ends of
 * an empty field.
 * ================================================================= */

.sc-facts--lean{
  width:max-content;
  max-width:100%;
  justify-content:flex-start;
  gap:1.2rem 2.5rem;
}

/*
 * auto-fit needs a definite width to fit anything to, and a max-content box
 * has none — so the two pairs stacked and pushed the button onto a second row
 * of an otherwise empty box. Told to flow along the row instead, the list
 * measures what it holds and the box measures the list.
 */
.sc-facts--lean .sc-facts__list{
  flex:0 1 auto;
  grid-template-columns:none;
  grid-auto-flow:column;
  grid-auto-columns:max-content;
}

/* On a phone the box is the width of the screen either way, app.css already
   gives the button the full width of it, and two facts side by side would not
   fit — so the ordinary stacking comes back. */
@media (max-width:560px){
  .sc-facts--lean{
    width:100%;
  }
  .sc-facts--lean .sc-facts__list{
    grid-template-columns:repeat(auto-fit,minmax(9rem,max-content));
    grid-auto-flow:row;
  }
  /* app.css already asks for a full-width button here; flex:0 0 auto meant it
     only ever filled its own content width. */
  .sc-facts--lean .sc-facts__go{
    flex:1 1 100%;
  }
}

/* ====================================================================
 * 4. The gallery
 *
 * Two problems, one section. The grid reserved five columns for however many
 * pictures there were, and the single picture there usually is was the cover
 * again — because what the import filed beside each cover is the same site
 * captured top to bottom, which cropped to a 3:2 thumbnail and anchored to its
 * top edge is the hero, pixel for pixel.
 *
 * single-portfolio.php now recognises that image by its proportions and this
 * shows it at them. Same file, different thing entirely: the whole page.
 * ================================================================= */

/* One picture is never half of a two-column grid, at any width. */
.sc-gallery__grid[data-shots="1"]{
  grid-template-columns:minmax(0,1fr);
}

/* Two pictures are two columns from the point there is room for two. */
@media (min-width:760px){
  .sc-gallery__grid[data-shots="1"]{max-width:560px}
  .sc-gallery__grid[data-shots="2"]{grid-template-columns:repeat(2,minmax(0,1fr));max-width:760px}
}

/*
 * At the full measure auto-fill lays five tracks and fills as many as it can,
 * which is right for a lot of pictures and wrong for a few: two left three
 * columns of nothing, and seven left a row of two beside a row of five. The
 * counts a project actually has are given a column count that comes out even.
 * Above eight, auto-fill is doing the right thing again.
 */
@media (min-width:1000px){
  .sc-gallery__grid[data-shots="3"]{grid-template-columns:repeat(3,minmax(0,1fr))}
  .sc-gallery__grid[data-shots="4"]{grid-template-columns:repeat(4,minmax(0,1fr))}
  .sc-gallery__grid[data-shots="6"]{grid-template-columns:repeat(3,minmax(0,1fr))}
  .sc-gallery__grid[data-shots="7"],
  .sc-gallery__grid[data-shots="8"]{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* The full-page capture. */
.sc-gallery--full .sc-section-title{
  text-align:center;
}
/* The grid is the figure: it stops at the width of the thing in it rather than
   claiming the whole measure and leaving a hole where four more would go. */
.sc-gallery--full .sc-gallery__grid{
  max-width:min(100%,620px);
  margin-inline:auto;
}

.sc-shot--full{
  position:relative;
  /* Portrait, because a page is; bounded, because these run to 1:5.3 and an
     unbounded one would be two and a half thousand pixels of scroll. The rest
     is a click away, which is what the label says. */
  aspect-ratio:3/4;
  max-width:min(100%,620px);
  margin-inline:auto;
  border-radius:var(--radius);
  box-shadow:var(--shadow);
}

/* The page fading out under the label is the whole message: there is more of
   this, and it is not being hidden from you. */
.sc-shot--full::after{
  content:"";
  position:absolute;
  inset:auto 0 0 0;
  height:42%;
  background:linear-gradient(to bottom,transparent,var(--bg) 94%);
  pointer-events:none;
}

.sc-shot__label{
  position:absolute;
  left:50%;
  bottom:18px;
  z-index:1;
  display:inline-flex;
  align-items:center;
  min-height:44px;
  padding:.5rem 1.35rem;
  transform:translateX(-50%);
  border:1.5px solid var(--line);
  border-radius:var(--radius-pill);
  background:var(--bg);
  box-shadow:var(--shadow);
  color:var(--ink);
  font-size:.9rem;
  font-weight:600;
  line-height:1.2;
  white-space:nowrap;
  transition:background .2s ease,border-color .2s ease,color .2s ease;
}
.sc-shot--full:hover .sc-shot__label,
.sc-shot--full:focus-visible .sc-shot__label{
  background:var(--red);
  border-color:var(--red);
  color:#fff;
}

/* ===================================================================
   BLOG + ACCESSIBILITY - focus ring, separators, legibility, orphan rows
   (was assets/parts/blog2.css)
   =================================================================== */

/*
 * Blog, second pass — what a full render at 360, 768 and 1440 found.
 *
 * Merges into app.css and loads after it. Every colour, size and measure below
 * is read from the tokens app.css :root already declares; this file declares
 * none of its own, so nothing here can drift away from the design system.
 *
 * Rules in app.css this file overrides, and why:
 *
 *   .search-form__field:focus{outline:none}      the field was the one control
 *   .search-form:focus-within{border-color:...}  on the site with no focus
 *                                                indicator of its own
 *   .aa-dot{color:var(--line)}                   1.18:1 — a separator nobody
 *   .aa-crumbs__sep{color:var(--line)}           can see is not a separator
 *   .aa-card__excerpt{font-size:.9375rem}        15px of prose on a phone
 *   .aa-cta__note{font-size:.9375rem}            15px of prose on a phone
 *   .search-form__field{font-size:.95rem}        15.2px in an input is what
 *                                                makes iOS Safari zoom the
 *                                                page on focus
 *   .aa-postnav__label{font-size:.72rem}         11.52px, where this theme's
 *   .aa-toc__label{font-size:.72rem}             one eyebrow size is .75rem
 *   .btn{font-size:.975rem}                      inside .aa-cta and the 404
 *                                                only; the header's own CTA is
 *                                                chrome and is left to it
 */


/* ---- Search field focus ------------------------------------------------
 *
 * app.css took the field's outline away and let the wrapper's border carry
 * the state instead. But :focus-within fires for the submit button sitting
 * next to it as well, so the same one-pixel border change meant two different
 * things and a keyboard user could not tell which control they were on.
 *
 * The field gets the ring, drawn around the whole pill because that is the
 * shape the caret is inside; the button keeps the round ring the site's
 * :focus-visible rule already gives it. Two controls, two pictures. The
 * border change is narrowed to the field so it agrees with the ring rather
 * than contradicting it.
 *
 * The plain rule comes first and is enough on its own; the @supports block
 * moves the ring outward where :has() can ask which child has focus.
 */
.search-form__field:focus-visible{
  outline:2px solid var(--red);
  outline-offset:2px;
  border-radius:var(--radius-pill);
}

@supports selector(:has(*)){
  .search-form__field:focus-visible{outline:none}

  .search-form:has(.search-form__field:focus-visible){
    outline:2px solid var(--red);
    outline-offset:2px;
    border-color:var(--ink);
  }

  .search-form:focus-within:not(:has(.search-form__field:focus)){
    border-color:var(--line);
  }
}


/* ---- Separators --------------------------------------------------------
 *
 * --line is a hairline colour: it is right for a 1px rule and wrong for type.
 * At 13–14px it put the breadcrumb slash and the meta middot at 1.18:1 on
 * white, which is not a low-contrast separator but an absent one — "Home Blog
 * Secure Your Data with NextCloud" arrives as one run-on phrase.
 *
 * Both are aria-hidden, so this was never a WCAG failure; it was a legibility
 * one. Mixed 80% into the grey the text beside them already uses, they land at
 * about 4:1 — plainly visible, still visibly subordinate to the 6.6:1 words
 * they separate. The flat --grey above is the fallback for a browser without
 * color-mix, and passes on its own.
 */
.aa-dot,
.aa-crumbs__sep{
  color:var(--grey);
  color:color-mix(in srgb, var(--grey) 80%, var(--bg));
}


/* ---- Type that measured too small --------------------------------------
 *
 * Raised: the two places a card or a call to action sets real prose, the
 * search input, and the buttons that end an article and a 404.
 *
 * Not raised: .t-eyebrow at 12px, .aa-card__meta and .aa-article__caption and
 * .aa-tag at 13px, .aa-crumbs at 14px, .aa-article__meta at 14px. Those are
 * labels and datelines, they are meant to sit under the reading size, and
 * pushing them all to 16px would flatten the page's hierarchy to fix a number
 * rather than a problem. Body prose already measures 17.6–18px.
 */
.aa-card__excerpt{font-size:1rem}
.aa-cta__note{font-size:1rem}
.search-form__field{font-size:1rem}

/* The lead card's excerpt is already 1rem from 760px up; this keeps the two
   the same size below it rather than making the lead the smaller of the two. */
@media (min-width:760px){
  .aa-card--lead .aa-card__excerpt{font-size:1.0625rem}
}

/* One eyebrow size on the site. These two had drifted to .72rem, which is
   11.52px — under both the 12px the rest of the theme uses and anything
   comfortable on a phone. This is an alignment, not a blanket raise. */
.aa-postnav__label,
.aa-toc__label{font-size:.75rem}

/* The one button at the end of an article and the two on the 404 — the calls
   to action in the views this file owns. Scoped, so the header's nav CTA
   stays whatever the chrome decides it is. */
.aa-cta .btn,
.error-404__actions .btn{font-size:1rem}


/* ---- The last card on the row ------------------------------------------
 *
 * .aa-cards--odd is set in PHP, where the number of cards is actually known:
 * it means the two-column step would leave the final card alone beside a gap.
 * Three related posts did exactly that at 768, and so did nine cards on an
 * archive.
 *
 * The answer is the one this theme already uses at the top of the blog index:
 * a card laid on its side across the full width. It ends the grid flush, it
 * reads as a decision rather than a card that failed to load, and it needs no
 * new component — the lead card has been this shape all along.
 *
 * Only the two-column step. At three columns nothing in this content leaves a
 * lone card, and a card stretched across 1200px to close a gap would be a
 * worse picture than the gap.
 */
@media (min-width:700px) and (max-width:1039.98px){
  .aa-cards--odd > .aa-card:last-child{grid-column:1/-1}

  .aa-cards--odd > .aa-card:last-child:not(.aa-card--bare){
    display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,1.2fr);
    align-items:center;
    gap:clamp(28px,3.4vw,40px);
  }

  .aa-cards--odd > .aa-card:last-child .aa-card__body{
    padding-top:0;
    justify-content:center;
  }

  .aa-cards--odd > .aa-card:last-child .aa-card__meta{
    margin-top:1.1rem;
    padding-top:0;
  }

  /* A result with no picture has nothing to put in the first column, so it
     stays a block and is held to a readable measure instead. */
  .aa-cards--odd > .aa-card--bare:last-child .aa-card__body{max-width:60ch}
}


/* ---- Headings a view had gone without ----------------------------------
 *
 * An empty archive, an empty search and the 404 each rendered an h1 and then
 * no heading at all, which put a footer column label first in the outline.
 * The type comes from .t-h3 in the markup; these only set the rhythm around
 * it. .error-404__inner is a grid and spaces its own children.
 */
.aa-empty__title{margin:2rem 0 0}
.aa-empty__title + .aa-suggest{margin-top:1rem}
.aa-empty__title + .search-form{margin-top:1rem}


/* ---- Headings recovered from bold --------------------------------------
 *
 * Every post here labels its one list with a bold paragraph rather than a
 * heading. inc/blog.php promotes those to h2 so the article has an outline;
 * this keeps the promotion from also changing the picture. A label introducing
 * a three-item list is not a section of an essay: it takes the size of the
 * heading below it and the air of the one above, so the page still reads the
 * way the writer laid it out while the document finally has a structure.
 */
.aa-prose h2.aa-prose__label{
  font-size:clamp(1.15rem,1.7vw,1.35rem);
  margin:1.7em 0 .5em;
}

/* ---- Copy left, offer right ------------------------------------------
   One argument beside one price, so a reader can weigh them together
   rather than meeting the price a screen later with an empty column
   beside it the whole way down.

   Stacked below 900px: side by side, neither half gets a usable measure
   on a phone, and the offer is the thing a reader on a phone is scrolling
   to reach - putting it second is right there.

   The card sticks on a long page so the price stays in view while the
   argument is still being read. align-self:start is what lets it: a grid
   item stretches by default, and a stretched item cannot stick. */
.aa-offer{
  display:grid;
  gap:clamp(28px,3.6vw,56px);
  align-items:start;
  margin-bottom:clamp(36px,4.5vw,64px);
}
.aa-offer__copy > *{max-width:none}

@media (min-width:900px){
  .aa-offer{grid-template-columns:minmax(0,1fr) minmax(0,420px)}
  .aa-offer__card{position:sticky;top:calc(var(--aa-header-h,75px) + 24px);align-self:start}
}

/* The card is the whole of its column here, so the rule that centres a
   lone offer in a 1200px wrap must not also apply inside it. */
.aa-offer__card .aa-grid{display:block;max-width:none;width:auto;margin:0}
.aa-offer__card .aa-plan{margin:0}

/* ---- Systems cards, tightened -----------------------------------------
   The four cards were correct but read as a wall of stacked labels: RENT
   above BUY above maintenance above features, so a reader scanned down one
   card at a time when the whole point of a four-up row is to compare
   across it. Rent and Buy now sit side by side - they are the same
   decision, not two - which also halves the vertical run and brings the
   feature lists onto one line of sight.

   The red rule at the top gives each card an edge to start at, and picks
   up the same 30x3 mark used over every h2 on the site. */
.aa-systems .aa-plan{
  position:relative;
  padding-top:calc(clamp(20px,2vw,28px) + 6px);
  overflow:hidden;
}
.aa-systems .aa-plan::before{
  content:"";
  position:absolute;inset-inline:0;top:0;height:3px;
  background:var(--red);
}
.aa-systems .aa-plan:target::before{height:5px}

/* Rent and Buy as a pair, not a stack. */
.aa-systems .aa-plan__prices{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:.35rem 1rem;
  align-items:start;
}
.aa-systems .aa-plan__prices > div{min-width:0}
.aa-systems .aa-plan__prices dt{
  font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--red);font-weight:600;margin-bottom:.15rem;
}
.aa-systems .aa-plan__prices dd{
  margin:0;
  font-size:clamp(1.3rem,1.7vw,1.55rem);
  font-weight:700;line-height:1.1;color:var(--ink);
  letter-spacing:-.02em;
}
.aa-systems .aa-plan__prices dd span{
  display:block;
  font-size:.75rem;font-weight:400;letter-spacing:0;
  color:var(--grey);margin-top:.15rem;
}

/* The maintenance line belongs with the prices, not adrift under them. */
.aa-systems .aa-plan__prices + .t-small{
  margin-top:.85rem;padding-top:.7rem;
  border-top:1px solid var(--line);
  color:var(--grey);
}

/* ---- Product logos in an offer card ----------------------------------
   Three logos supplied three different ways - one small mark on white with
   its own padding baked in, one gradient tile, one full-bleed orange block
   - read as three different kinds of thing rather than three products of
   the same kind. A shared frame is what makes them a set: the same height,
   the same ground, each logo contained inside it at its own aspect ratio
   rather than cropped or stretched to fit.

   object-fit:contain, not cover: a logo is the one image on a page that
   must never be cropped. */
.aa-plan > figure:first-child{
  margin:0 0 1.15rem;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  aspect-ratio:16/9;
  display:grid;
  place-items:center;
  overflow:hidden;
  padding:clamp(14px,2vw,22px);
}
.aa-plan > figure:first-child img{
  width:100%;height:100%;
  object-fit:contain;
  object-position:center;
}
