  :root{
    --bg:#100807;
    --fg:#f1ede5;
    --muted:rgba(241,237,229,.55);
    --line:rgba(241,237,229,.18);
    /* --line-projects is the works-list project rows' hairline. Its
       alpha is admin-controlled (STYLE → COLORS → HAIRLINE OPACITY);
       defaults match --line so a fresh deploy looks identical until
       the admin edits it. */
    --line-projects:rgba(241,237,229,.18);
    --accent:#e8443c;
    --seal-color:#e8443c;
    --display-font:"Haywire ExtraCondensed","Barlow Condensed", sans-serif;
    /* Project-name surfaces (.v2-list-name + .pp-title + .pp-next-name)
       read these two vars for weight + casing. Inline values match the
       admin's default pick. An inline <script> in <head> overrides
       them from localStorage BEFORE the first paint, and the runtime
       <style id="nv-style"> later re-asserts them — but with the same
       resolved values, so no visible change between paint frames. */
    --projects-weight:200;
    --projects-case:uppercase;
    /* .v2-list-name (home works list) size. Admin-controlled via STYLE
       → TYPOGRAPHY → PROJECT NAMES → SIZE. Mobile scales to 80% of this
       value automatically via a calc() override below the breakpoint. */
    --projects-size:20px;
    --serif:"Instrument Serif", serif;
    --mono:"JetBrains Mono", ui-monospace, monospace;
    --wordmark-scale:1;
    /* Shared values so topbar and footer bands have identical geometry. */
    --bar-pad-y:clamp(14px, 1.75vh, 22px);
    --bar-inset:clamp(16px, 4vw, 56px);
  }
  @font-face{
    font-family:"Tusker Grotesk 3700 Bold";
    src:url("/fonts/TuskerGrotesk-3700Bold.woff2") format("woff2"),
        url("/fonts/TuskerGrotesk-3700Bold.woff") format("woff"),
        url("/fonts/TuskerGrotesk-3700Bold.ttf") format("truetype");
    font-weight:400;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Haywire Condensed";
    src:url("/fonts/Haywire-Condensed.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Marigold Sans";
    src:url("/fonts/MarigoldSans.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Haywire ExtraCondensed";
    src:url("/fonts/Haywire-ExtraCondensed.woff2") format("woff2"),
        url("/fonts/Haywire-ExtraCondensed.woff") format("woff"),
        url("/fonts/Haywire-ExtraCondensed.ttf") format("truetype");
    font-weight:400;font-style:normal;font-display:block;
  }
  /* font-display:block on the four new display fonts — text using them
     stays INVISIBLE during the (max 3s) font-loading block period
     instead of flashing fallback glyphs first, eliminating the
     visible "swap" from fallback to the real font. Combined with the
     dynamic preload in the head <script> above, the picked font is
     usually ready well within the block period. */
  @font-face{
    font-family:"Sunliner Revival";
    src:url("/fonts/SunlinerRevival.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Evangelina";
    src:url("/fonts/Evangelina.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Silvera";
    src:url("/fonts/Silvera.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  @font-face{
    font-family:"Sophillia";
    src:url("/fonts/Sophillia.otf") format("opentype");
    font-weight:100 900;font-style:normal;font-display:block;
  }
  html,body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--mono);
    width:100%;min-height:100vh;overflow-x:hidden;}
  .root-stage{width:100vw;min-height:100vh;display:flex;}
  .root-stage>.ab{flex:1;min-height:100vh;}
  a{color:inherit;text-decoration:none;cursor:pointer;}
  *{box-sizing:border-box;}

  /* ── Artboard shell ───────────────────────────────────────────────── */
  .ab{
    position:relative;width:100%;height:100%;
    background:var(--bg);color:var(--fg);
    padding:42px 56px 36px;
    display:flex;flex-direction:column;
    overflow:hidden;
  }
  .display{font-family:var(--display-font);font-weight:900;letter-spacing:-.01em;line-height:.9;}
  /* Project-name surfaces — all three pull family, weight, and casing
     from the same CSS variables. The inline <script> at the top of
     <body> sets these vars from localStorage before first paint
     (eliminating the FOUC jump); the React style-runtime later
     overwrites the vars with the live admin state — same resolved
     values, no relayout. font-family also comes from the var here
     so .display's hard-coded font-weight:900 doesn't override us. */
  .v2-list-name,.pp-title,.pp-next-name{
    font-family:var(--display-font);
    font-weight:var(--projects-weight);
    text-transform:var(--projects-case);
  }
  .serif-it{font-family:var(--serif);font-style:italic;font-weight:400;line-height:1.18;}
  .mono{font-family:var(--mono);}
  .xs{font-size:11px;letter-spacing:.12em;text-transform:uppercase;}
  .xxs{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;}
  .muted{color:var(--muted);}
  .accent{color:var(--accent);}

  /* ── Generic header / footer / intro / works ─────────────────────── */
  .hd{display:flex;justify-content:space-between;align-items:center;}
  .hd-nav{display:flex;gap:36px;}
  .hd-mid{flex:0 1 auto;text-align:center;white-space:nowrap;letter-spacing:.18em;}
  /* V2-only: hairline below the topbar and above the footer (the mockup
     uses both as horizontal dividers framing the wordmark band). Scoped
     to direct children of `.ab.v2` so project / studio / contact pages
     keep their own `pp-hd` / `pp-ft` chrome. */
  /* Topbar: gap above the text (.ab.v2 padding-top) matches the gap
     below it (this padding-bottom). Same total spacing top/bottom of
     the text → symmetric framing of the topbar text within its band. */
  /* position:sticky keeps the topbar pinned to viewport top once the user
     scrolls past it, without removing it from the flex flow (so we don't
     need an extra padding-top on .ab.v2 to compensate). z-index:20 puts
     it in the same stacking band as the fixed footer. The vertical
     padding lives inside .hd now (was previously delegated to .ab.v2's
     padding-top) so the same bar-pad-y breathing space is preserved
     whether the bar is in flow or stuck. */
  .ab.v2 > .hd{position:sticky;top:0;z-index:20;background:var(--bg);
    border-bottom:1px solid var(--line);
    padding-top:var(--bar-pad-y);padding-bottom:var(--bar-pad-y);}
  /* Footer flows with the page (no longer pinned to the viewport bottom).
     It sits at the natural bottom of the document, scrolling away with
     the rest of the content. Hairline still appears above the © /
     INSTAGRAM line so the bar reads the same visually. */
  .ab.v2 > .ft{
    border-top:1px solid var(--line);
    padding-top:clamp(14px, 1.7vh, 22px);
    padding-bottom:clamp(14px, 1.7vh, 22px);
    padding-left:0;padding-right:0;
    margin:0;
    line-height:1;
    display:flex;align-items:center;}
  .ft{display:flex;justify-content:space-between;align-items:center;margin-top:auto;padding-top:18px;}
  .ft-right{display:flex;gap:36px;}

  .intro{display:flex;flex-direction:column;gap:18px;max-width:24ch;}
  .intro p{margin:0;font-size:22px;}
  .intro-sm p{font-size:18px;}

  .works{
    list-style:none;margin:0;padding:0;
    display:grid;grid-template-columns:auto auto 1fr auto auto;
    column-gap:32px;row-gap:0;
    border-top:1px solid var(--line);
    align-self:stretch;
  }
  .works-head{display:contents;}
  .works-head>span:last-child{grid-column:5;justify-self:end;padding:14px 0;}
  .works-compact .work{padding:9px 0;}
  .work{display:contents;}
  .work>*{padding:14px 0;border-bottom:1px solid var(--line);align-self:center;}
  .work-name{font-size:30px;}
  .work-meta{justify-self:start;}

  .imgbox{
    width:100%;height:100%;min-height:120px;
    background:
      repeating-linear-gradient(135deg,
        rgba(241,237,229,.05) 0 8px, rgba(241,237,229,.02) 8px 18px);
    border:1px solid var(--line);
    display:flex;align-items:flex-end;padding:14px;position:relative;
  }
  .imgbox-b{background:
      repeating-linear-gradient(45deg,
        rgba(241,237,229,.06) 0 6px, rgba(241,237,229,.015) 6px 16px);}
  .imgbox-c{background:
      repeating-linear-gradient(0deg,
        rgba(241,237,229,.05) 0 4px, rgba(241,237,229,.02) 4px 14px);}
  .imgbox-label{opacity:.65;}
  /* Real-photo variant — no stripes, no padding, image fills the box.
     Triggered by ImgBox when `src` is set (e.g. Cloudinary URL). */
  .imgbox-real{background:#000;padding:0;overflow:hidden;align-items:stretch;}
  .imgbox-real img{width:100%;height:100%;object-fit:cover;display:block;}

  /* ── V1 — direct dark conversion ─────────────────────────────────── */
  .v1-mark{margin-top:8px;}
  .v1-row{display:grid;grid-template-columns:280px 1fr;gap:80px;margin-top:24px;}

  /* ── V2 — bezier wave ──────────────────────────────────────────────
     Fluid scaling: wordmark, ticker and seal scale together with the
     viewport via clamp(), so spacing is coherent at every width.        */
  /* V2 spacing model: everything vertical scales with viewport WIDTH (vw),
     so it stays in proportion to the wordmark (which is sized by width).
     The wordmark width is capped so on ultra-wide screens it doesn't grow
     unbounded — that was the source of the topbar collision. */
  /* height:auto undoes the .ab base's `height:100%` for V2 specifically.
     Without it the artboard is pinned to 100vh as a flex column, the
     expanded works list overflows visibly out of the bottom but the
     container doesn't grow, html/body stay at 100vh, and the window
     can't scroll to reach the rows that fell below the fixed footer.
     min-height:100vh keeps the empty-state filling the viewport.
     Padding-top is 0: the sticky .hd owns its own vertical breathing
     space now, so duplicating it on .ab.v2 would push the wordmark
     down twice. Padding-bottom is small breathing room above the
     in-flow footer (the footer no longer overlaps content, so no
     reserve is needed). */
  .ab.v2{overflow:visible;height:auto;min-height:100vh;
    padding:0 var(--bar-inset) 0;}
  /* Desktop layout (>1100px): a single full-width flex row split into
     two named columns — wordmark on the left at 80%, seal on the right
     at 20%. Both columns top-align so the wordmark's cap-line and the
     seal's top edge sit on the same horizontal. */
  .v2-mark{flex:0 0 auto;display:flex;align-items:flex-start;justify-content:flex-start;
    gap:0;
    width:100%;align-self:stretch;
    margin-top:clamp(50px, 8vh, 110px);
    /* The wordmark SVG element's bottom now coincides with the visible
       baseline (unified viewBox). The gap to the works list is set as a
       fraction of the artboard's content width so it scales 1:1 with
       the wordmark itself — keeping the visual relationship between the
       glyph baseline and the first project row invariant as the user
       resizes. (Fixed-px gap would feel "wrong" at extreme widths
       because the wordmark grows but the gap doesn't.) */
    margin-bottom:calc(0.04 * (100vw - 2 * var(--bar-inset)));}
  .v2-wordmark{flex:0 0 80%;max-width:80%;min-width:0;}
  .v2-wordmark svg{display:block;width:100%;height:auto;}
  /* Seal box: 20% column on the right; the seal-mark anchors to the
     top-LEFT inside that column so the brand mark sits right next to
     the wordmark's right edge instead of pinned to the artboard's
     outer corner. */
  .v2-mark > .v2-seal{flex:0 0 20%;max-width:20%;
    display:flex;justify-content:flex-start;align-items:flex-start;
    padding:0;}
  /* The seal is rendered as a luminance mask over a cream-coloured div:
     where the source SVG is white the cream shows; where it is black the
     mask is fully transparent and the page background passes through.
     This sidesteps the brittle path-color editing — the SVG file stays
     byte-identical to seal.svg, the recolour is entirely a CSS concern. */
  .v2-mark > .v2-seal .v2-seal-mark{
    width:clamp(86px, 8.64vw, 158px);height:clamp(86px, 8.64vw, 158px);
    /* The seal's horizontal position is now JS-controlled in
       src/variants.jsx (align effect): on desktop it tracks the
       wordmark's visible right edge plus a constant pixel gap, so the
       gap stays the same on every viewport. No CSS margin-left
       fallback — JS pins to 0 before reading natural position and
       overrides with the computed value. */
    /* Seal fill colour is its own admin-editable swatch (STYLE → COLORS →
       SEAL), defaulting to the same red as --accent. Falls back to --fg if
       --seal-color is unset for any reason. */
    background-color:var(--seal-color, var(--fg));
    -webkit-mask:url('/src/assets/seal-mark.svg') no-repeat center / contain;
    mask:url('/src/assets/seal-mark.svg') no-repeat center / contain;
    -webkit-mask-mode:luminance;
    mask-mode:luminance;}
  .ab.v2 > header,
  .ab.v2 > .v2-mark,
  .ab.v2 > .py-ticker,
  .ab.v2 > .v2-bottom{flex:0 0 auto;}
  .ab.v2 > footer.ft{margin-top:auto;flex:0 0 auto;}
  .v2-panel{position:absolute;top:80px;right:48px;width:240px;z-index:5;
    background:rgba(20,18,16,.9);border:1px solid rgba(241,237,229,.18);
    padding:14px 14px 12px;font-family:var(--mono);color:var(--fg);
    backdrop-filter:blur(8px);}
  .v2-panel-hd{display:flex;justify-content:space-between;align-items:center;
    font-size:10px;letter-spacing:.18em;color:var(--muted);
    border-bottom:1px solid var(--line);padding-bottom:8px;margin-bottom:10px;}
  .v2-panel-btn{background:transparent;border:1px solid var(--line);color:var(--fg);
    font-family:var(--mono);font-size:9px;letter-spacing:.1em;padding:3px 8px;cursor:pointer;}
  .v2-panel-btn:hover{background:var(--accent);border-color:var(--accent);}
  .v2-panel-hint{font-size:9px;letter-spacing:.14em;color:var(--muted);text-transform:uppercase;
    margin-top:8px;padding-top:8px;border-top:1px solid var(--line);}
  .v2-knob{display:grid;grid-template-columns:1fr 90px 32px;align-items:center;gap:8px;padding:3px 0;}
  .v2-knob-l{font-size:10px;letter-spacing:.08em;color:var(--muted);text-transform:uppercase;}
  .v2-knob-v{font-size:10px;color:var(--fg);text-align:right;font-variant-numeric:tabular-nums;}
  .v2-knob input[type=range]{
    -webkit-appearance:none;appearance:none;width:100%;height:2px;
    background:rgba(241,237,229,.2);outline:none;}
  .v2-knob input[type=range]::-webkit-slider-thumb{
    -webkit-appearance:none;width:10px;height:10px;border-radius:50%;
    background:var(--accent);cursor:pointer;}
  .v2-knob input[type=range]::-moz-range-thumb{
    width:10px;height:10px;border-radius:50%;background:var(--accent);
    border:0;cursor:pointer;}
  .v2-styles{display:grid;grid-template-columns:repeat(2,1fr);gap:4px;margin:0 0 10px;}
  .v2-style{
    background:transparent;border:1px solid var(--line);color:var(--muted);
    font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
    padding:5px 4px;cursor:pointer;text-transform:uppercase;
  }
  .v2-style:hover{color:var(--fg);}
  .v2-style.is-on{background:var(--accent);border-color:var(--accent);color:#0a0908;}
  /* ── V2 · ticker payoff + works list ──────────────────────────────
     Ticker scales fluidly: height + font-size all on clamp() so the
     band stays proportional to the wordmark above.                     */
  .py{padding:0;}
  .py-ticker{
    overflow:hidden;
    border-top:1px solid var(--line);border-bottom:1px solid var(--line);
    height:clamp(26px, 3vw, 34px);
    padding-top:2px;display:flex;align-items:center;
    margin-top:clamp(-12px, -1vw, -8px);
    position:relative;
  }
  .py-tk-lift{transform:translateY(-0.18em);width:100%;}
  .py-tk-track{display:flex;gap:0;white-space:nowrap;align-items:center;
    animation:py-marquee 50s linear infinite;}
  /* 10 identical phrases are tiled flush across the track so the viewport
     is already full of text at page load. Animating exactly one phrase
     width per cycle (-10%) keeps the loop seamless. */
  .py-tk-phrase{display:flex;align-items:center;
    gap:clamp(10px, 2vw, 24px);padding-right:clamp(14px, 2.2vw, 28px);}
  /* All ticker text inherits font-size/weight from .py-ticker so it
     can be tuned in one place (currently 14px / 200).               */
  .py-tk-h{font-size:inherit;font-weight:inherit;line-height:1;letter-spacing:-.005em;}
  .py-tk-i{font-size:inherit;font-weight:inherit;line-height:1;color:var(--muted);}
  .py-tk-dot{font-size:inherit;font-weight:inherit;line-height:1;color:var(--muted);}
  @keyframes py-marquee{from{transform:translateX(0);}to{transform:translateX(-10%);}}
  @keyframes nv-fade-in{from{opacity:0;}to{opacity:1;}}

  .v2-list{list-style:none;margin:18px 0 0;padding:0;display:flex;flex-direction:column;}
  /* Bottom row: works list pinned to the right.
     Default width = 40% of the artboard width. If a project name is too
     long to fit one line at that width, the list expands LEFT (the
     `width: max-content` resolves to the widest row's intrinsic width,
     bounded below by 40% and above by 100%). The mobile breakpoint
     flips it back to a full-width block. */
  .v2-bottom{display:flex;justify-content:flex-end;
    margin-top:0;}
  .v2-bottom .v2-list{margin-top:0;
    flex:0 1 auto;
    width:max-content;
    min-width:40%;
    max-width:100%;}
  /* MORE button when list is truncated.
     The wrapping <li> already gets a border-top from `.v2-list li`, so
     the button itself doesn't add one (that produced a visible 2px
     doubled hairline above the +). */
  .v2-more{display:flex;justify-content:center;
    padding:14px 0;cursor:pointer;background:transparent;border:0;
    color:var(--muted);font-family:var(--mono);
    font-size:11px;letter-spacing:.18em;text-transform:uppercase;width:100%;
    transition:color .2s ease, background .2s ease;}
  .v2-more:hover{color:var(--fg);background:rgba(241,237,229,.04);}
  /* Project rows use --line-projects so the admin's HAIRLINE OPACITY
     slider only affects these dividers, not the topbar / footer / other
     panels (which keep the fixed --line value). */
  .v2-list li{padding:0;border-top:1px solid var(--line-projects);}
  /* Close the table at the bottom — except when the last <li> is the
     "+ MORE" expander, which has its own border-top from .v2-list li and
     would otherwise paint a second hairline directly underneath the +. */
  .v2-list li:last-child:not(.v2-list-more-wrap){border-bottom:1px solid var(--line-projects);}
  .v2-list-head{display:grid;grid-template-columns:48px 1.2fr 2fr 80px;column-gap:24px;
    align-items:baseline;padding:6px 0 !important;}
  /* number | name | meta | year — four fixed-ratio columns so the table
     reads as a proper four-column grid regardless of any single project's
     name length. Number is content-sized (always two digits); name takes
     twice the share of name+meta+year so long titles like
     "PRADA - WORLDWIDE CAMPAIGN" fit, and meta + year each take 1fr.
     All metas land at the same x (left edge of column 3) and are
     left-aligned by default. Year is right-aligned inside its own
     column via justify-self:end so it sits flush with the table's
     right edge. */
  /* Name column uses minmax(max-content, 2fr): minimum width = the
     longest project name's natural width (forces one-line names; the
     list grows left from its 40% basis to fit), maximum grows as 2fr
     when the row has spare width. */
  .v2-list-row{display:grid;grid-template-columns:48px minmax(max-content, 2fr) 1fr 0.5fr;
    column-gap:12px;
    /* Symmetric padding so the .v2-list-name content box centers
       between the row's top/bottom hairlines. The 4 px below also
       defines the gap between the project name and the first preview
       thumbnail when the row is open — by pairing with
       .v2-list-preview-inner { padding-top: 0 } the thumbnails start
       exactly where the closed-state bottom hairline was, eliminating
       the double-gap that previously appeared on hover. */
    align-items:center;padding:4px 0;color:var(--fg);}
  .v2-list-row > span:nth-child(4){justify-self:end;}
  /* The home works-list project name shares the same family as the
     project page titles (.display) — both read --display-font, kept in
     sync at runtime by the admin's "PROJECT NAMES" font field. The
     size / weight remain independent (list = 20px / 200, titles use
     the .display rule). */
  /* white-space: nowrap so the name column's intrinsic max-content
     equals the full one-line width — that's what drives the .v2-list
     to expand left past its 40% basis when a long name doesn't fit.
     font-family + font-weight + text-transform come from the shared
     CSS vars set by the head <script> + style-runtime so the home
     list and project-page titles stay in lockstep. */
  .v2-list-name{font-size:var(--projects-size, 20px);line-height:1.1;white-space:nowrap;letter-spacing:0;}
  /* B&W preview strip — same images as project page stills.
     Open state (`.is-open`) is set by JS:
       • on hover-capable devices when the mouse pointer enters the row,
         and cleared 2s after the mouse leaves;
       • on touch devices on the first tap (which is also swallowed so
         it doesn't navigate); the row auto-closes after 2s unless the
         user taps it again to confirm.
     Open transition is snappy; close transition is slow (~0.9s) — the
     2s linger between pointer-leave and close is timed in JS, not CSS. */
  .v2-list-preview{display:grid;grid-template-rows:0fr;
    opacity:0;overflow:hidden;
    /* Block max-content propagation from the thumbnail strip up into
       .v2-list's `width: max-content`. Without this an <img> child
       (Cloudinary URLs serve their natural ~1500-2000 px width) drags
       the whole works list to full viewport width — minmax(0, 1fr) on
       the inner grid caps the MIN intrinsic size but not the MAX
       (per the Grid spec, a <flex> max-track resolves to the items'
       max-content under a max-content constraint, even when minmax min
       is 0). `contain: inline-size` tells the browser "this element's
       inline-size is independent of its descendants", so ancestors
       size as if the preview were empty for intrinsic purposes. */
    contain:inline-size;
    transition:grid-template-rows .9s ease, opacity .6s ease;}
  .v2-list-li.is-open .v2-list-preview{grid-template-rows:1fr;opacity:1;
    transition:grid-template-rows .35s ease, opacity .25s ease;}
  /* Tracks are minmax(0, 1fr), not 1fr. Reason: .v2-bottom .v2-list has
     `width: max-content` (so the list grows to the longest project
     name), and in intrinsic-sizing context a plain `1fr` track degenerates
     to `max-content` of its items. Cloudinary stills have naturalWidth
     >1000px, so each thumb's max-content propagates up and drags
     .v2-list out to several thousand px — even while the preview row is
     closed (intrinsic sizing ignores grid-template-rows:0fr). minmax(0,
     1fr) caps the intrinsic max-content of each track at 0; the four
     thumbnails then share whatever width the .v2-list-row hands down,
     each scaling to 1/4 of it. */
  .v2-list-preview-inner{min-height:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
    /* No top padding: thumbnails start flush with the position where
       the closed-state bottom hairline was, so opening a row doesn't
       introduce a visible gap between the project name area and the
       thumbnails. */
    gap:8px;padding:0 0 6px;}
  /* Belt-and-suspenders min-width:0 on the flex/grid chain — the
     minmax(0, 1fr) above is the primary fix, this just makes sure the
     items themselves can also shrink below their min-content baseline
     in browsers that still honour the auto min behaviour somewhere up
     the chain. */
  .v2-list li,
  .v2-list-preview{min-width:0;}
  .v2-list-thumb{display:block;min-width:0;}
  /* min-height:0 overrides the global .imgbox{min-height:120px} which,
     when the list is narrow (short project names → narrow .v2-list →
     narrow thumb tracks), would dominate the 4/3 aspect-ratio and force
     each thumb tall + ugly instead of letting the ratio shrink the box. */
  .v2-list-thumb .imgbox{aspect-ratio:4/3;min-height:0;
    filter:grayscale(1) contrast(1.05) brightness(.95);
    transition:filter .25s ease;}
  .v2-list-thumb:hover .imgbox{filter:grayscale(0) contrast(1) brightness(1);}
  .v2-list-meta{font-size:11px;letter-spacing:.1em;text-transform:uppercase;}

  /* ── V3 — editorial split ────────────────────────────────────────── */
  .v3{padding:0;display:grid;grid-template-columns:46% 54%;}
  .v3-left{padding:42px 48px 36px;display:flex;flex-direction:column;gap:32px;border-right:1px solid var(--line);}
  .v3-mark{display:flex;flex-direction:column;gap:0;margin-top:8px;}
  .v3-mark svg{height:auto;}
  .v3-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;}
  .v3-list li{display:grid;grid-template-columns:32px 1fr auto;
    padding:10px 0;border-top:1px solid var(--line);}
  .v3-list li:last-child{border-bottom:1px solid var(--line);}
  .v3-right{position:relative;display:grid;grid-template-rows:1fr auto;background:#000;}
  .v3-caption{padding:24px 36px 36px;display:flex;flex-direction:column;gap:10px;
    border-top:1px solid var(--line);background:var(--bg);}
  .v3-feat{font-size:96px;}

  /* ── V4 — cinematic outline ──────────────────────────────────────── */
  .v4-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:48px;align-items:end;margin-top:36px;}
  .v4-mark{align-self:center;}
  .v4-feat{display:flex;flex-direction:column;gap:14px;padding-bottom:12px;}
  .v4-feat-name{font-size:96px;}
  .v4-feat-line{font-size:22px;}
  .v4-schedule{margin-top:auto;border-top:1px solid var(--line);}
  .v4-sched-head,.v4-sched-row{
    display:grid;grid-template-columns:60px 1.5fr 2fr 80px 80px;
    column-gap:24px;padding:12px 0;border-bottom:1px solid var(--line);align-items:center;
  }
  .v4-sched-head{padding:10px 0;}
  .v4-sched-title{font-size:28px;}

  /* ── V5 — marquee ticker ─────────────────────────────────────────── */
  .v5-marquee{margin:24px -56px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);overflow:hidden;}
  .v5-track{display:flex;gap:64px;white-space:nowrap;animation:v5slide 32s linear infinite;padding:18px 0;}
  .v5-tick{display:inline-flex;align-items:center;gap:64px;}
  .v5-mark{font-size:108px;line-height:.9;}
  .v5-dot{font-size:48px;line-height:.9;}
  @keyframes v5slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}
  .v5-thumbs{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-top:24px;height:200px;}
  .v5-row{display:grid;grid-template-columns:280px 1fr;gap:64px;margin-top:24px;}

  /* ── V6 — typo collage ───────────────────────────────────────────── */
  .v6-stack{flex:1;display:flex;flex-direction:column;gap:0;margin-top:16px;}
  .v6-divider{height:1px;background:var(--line);}
  .v6-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:32px;padding:6px 0;}
  .v6-row svg{max-width:78%;}
  .v6-aside{font-size:20px;max-width:18ch;}
  .v6-aside-r{text-align:right;}
  .v6-row-mark:nth-of-type(2){grid-template-columns:auto 1fr;}
  .v6-row-mark:nth-of-type(2) svg{margin-left:auto;max-width:62%;}
  .v6-projlist{list-style:none;margin:0;padding:0;}
  .v6-projlist li{display:grid;grid-template-columns:40px 1fr auto;
    column-gap:24px;padding:10px 0;align-items:center;}
  .v6-pname{font-size:42px;}

  /* ── V7 — index-first ────────────────────────────────────────────── */
  .v7-hd{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;}
  .v7-hd .hd-nav{justify-self:end;}
  .v7-tiny{font-size:18px;letter-spacing:.04em;color:var(--accent);}
  .v7-body{display:grid;grid-template-columns:1.4fr 1fr;gap:48px;flex:1;margin-top:32px;min-height:0;}
  .v7-list{display:flex;flex-direction:column;}
  .v7-intro{font-size:22px;margin:0 0 18px 0;max-width:30ch;}
  .v7-row{
    display:grid;grid-template-columns:30px 1fr 1.4fr 60px;column-gap:24px;align-items:center;
    padding:14px 0;border-top:1px solid var(--line);transition:padding-left .18s, color .18s;
  }
  .v7-row:last-child{border-bottom:1px solid var(--line);}
  .v7-row.is-hover{padding-left:14px;background:linear-gradient(90deg,rgba(232,68,60,.08),transparent 80%);}
  .v7-row.is-hover .v7-name{color:var(--accent);}
  .v7-name{font-size:34px;transition:color .2s;}
  .v7-preview{display:flex;flex-direction:column;gap:14px;}
  .v7-preview .imgbox{flex:1;}
  .v7-prev-meta{display:flex;flex-direction:column;gap:6px;}
  .v7-prev-name{font-size:46px;}

  /* ── V8 — brutalist mono ─────────────────────────────────────────── */
  .v8{font-family:var(--mono);padding:32px 40px;}
  .v8 a{text-decoration:underline;text-underline-offset:3px;}
  .v8-hd{display:flex;justify-content:space-between;font-size:12px;letter-spacing:.06em;
    border-bottom:1px solid var(--line);padding-bottom:12px;}
  .v8-mark{font-family:var(--mono);font-size:11px;line-height:1;color:var(--fg);
    margin:24px 0 0;white-space:pre;letter-spacing:0;}
  .v8-tag{font-size:12px;margin:18px 0 24px;letter-spacing:.06em;}
  .v8-table{width:100%;border-collapse:collapse;font-size:13px;}
  .v8-table th,.v8-table td{padding:11px 14px;text-align:left;border-bottom:1px dashed var(--line);
    letter-spacing:.06em;}
  .v8-table th{font-size:11px;color:var(--muted);font-weight:500;border-bottom:1px solid var(--line);}
  .v8-pname{font-size:18px;font-weight:500;}
  .v8-ft{display:flex;justify-content:space-between;margin-top:auto;padding-top:18px;font-size:12px;}

  /* ── V9 — STYLISH (Druk × Söhne spirit) ───────────────────────────
     Two faces only: Big Shoulders Display 900 (Druk Cond. Super analog)
     + IBM Plex Mono (Söhne Mono analog). No serif italic. Generous
     breathing. Hairline rules. Mono everywhere except the wordmark. */
  .v9{
    background:#0a0908;
    padding:46px 64px 40px;
  }
  .v9, .v9 *{
    font-family:"IBM Plex Mono", ui-monospace, monospace;
    font-weight:400;
  }
  .v9-hd{display:flex;justify-content:space-between;align-items:center;}
  .v9-hd>*{font-size:11px;letter-spacing:.18em;text-transform:uppercase;}
  .v9-hd .rt{display:flex;gap:48px;}
  .v9-mark{flex:1;display:flex;align-items:center;justify-content:center;margin:8px -12px 0;}
  .v9-mark svg{display:block;width:100%;height:auto;}
  .v9-mark text{
    font-family:"Big Shoulders Display","Barlow Condensed",sans-serif !important;
    font-weight:900;
  }
  .v9-row{display:grid;grid-template-columns:300px 1fr;gap:96px;margin-top:auto;padding-top:36px;}
  .v9-intro{display:flex;flex-direction:column;gap:18px;font-size:12px;line-height:1.55;
    letter-spacing:.06em;text-transform:uppercase;max-width:32ch;}
  .v9-intro p{margin:0;}
  .v9-intro p+p{color:var(--muted);}
  .v9-list{list-style:none;margin:0;padding:0;align-self:stretch;}
  .v9-list .v9-all{display:flex;justify-content:flex-end;font-size:10.5px;letter-spacing:.18em;
    text-transform:uppercase;color:var(--muted);padding:0 0 14px;border-bottom:1px solid var(--line);}
  .v9-row-item{
    display:grid;grid-template-columns:48px 1.1fr 2fr 64px 24px;column-gap:36px;align-items:center;
    padding:20px 0;border-bottom:1px solid var(--line);
    font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
    transition:padding-left .25s ease, color .25s ease;
  }
  .v9-row-item:hover{padding-left:14px;color:var(--fg);}
  .v9-row-item:hover .v9-pn{color:var(--accent);}
  .v9-row-item .v9-pn{
    font-family:"Big Shoulders Display","Barlow Condensed",sans-serif !important;
    font-weight:900;font-size:38px;letter-spacing:-.005em;color:var(--fg);
    line-height:1;text-transform:uppercase;
    transition:color .2s;
  }
  .v9-ft{display:flex;justify-content:space-between;align-items:center;margin-top:32px;
    font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);}
  .v9-ft .right{display:flex;gap:36px;}
  .v9-ft a:hover{color:var(--fg);}

  /* canvas backdrop tweak — make the dark artboards pop on the warm canvas */
  body{background:var(--bg);}

  /* ── Project page ───────────────────────────────────────────────── */
  .pp{background:var(--bg);color:var(--fg);width:100%;}
  /* Project page top bar — chrome matched to .ab.v2 > .hd (same border,
     same padding rhythm, no sticky/backdrop) so navigating from home
     to a project page feels like the same site, not a separate
     layout. The grid template is kept (1fr auto 1fr) because pp-hd
     has three areas where the home topbar only has two. */
  /* Same sticky treatment as the home topbar (.ab.v2 > .hd) — pinned to
     viewport top once scrolled past, stays in flow otherwise. */
  .pp-hd{position:sticky;top:0;z-index:20;background:var(--bg);
    display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
    padding:var(--bar-pad-y) var(--bar-inset);border-bottom:1px solid var(--line);}
  .pp-back{justify-self:start;color:var(--fg);}
  .pp-back:hover{color:var(--accent);}
  .pp-hd-mid{justify-self:center;color:var(--muted);}
  .pp-hd .hd-nav{justify-self:end;}

  /* Project-not-found state: same .pp shell, but a typographic
     placeholder instead of hero/synopsis/etc. Mirrors the visual
     rhythm of /404.html (mono caption + display title + back link). */
  .pp-404{min-height:100vh;display:flex;flex-direction:column;}
  .pp-404-body{flex:1;display:flex;flex-direction:column;justify-content:center;
    gap:24px;padding:120px 56px;}
  .pp-404-back{display:inline-flex;align-items:center;width:fit-content;
    padding-top:18px;border-top:1px solid var(--line);}
  .pp-404-back:hover{color:var(--accent);}

  .pp-hero{position:relative;height:88vh;min-height:640px;}
  .pp-hero-img{position:absolute;inset:0;}
  .pp-hero-img .imgbox{height:100%;border:0;border-bottom:1px solid var(--line);}
  .pp-hero-overlay{position:absolute;inset:0;display:grid;
    grid-template-columns:1fr 1fr;grid-template-rows:auto 1fr auto;
    padding:36px 56px;pointer-events:none;}
  .pp-hero-overlay .mono, .pp-hero-overlay button{pointer-events:auto;}
  .pp-hero-tl{grid-row:1;grid-column:1;display:flex;gap:14px;align-items:center;}
  .pp-hero-tr{grid-row:1;grid-column:2;justify-self:end;display:flex;gap:10px;align-items:center;}
  .pp-hero-bl{grid-row:3;grid-column:1;display:flex;flex-direction:column;gap:14px;align-self:end;
    max-width:50ch;}
  .pp-title{font-size:clamp(64px,9vw,148px);line-height:.88;letter-spacing:-.02em;}
  .pp-tagline{font-size:24px;color:var(--fg);max-width:34ch;}
  .pp-hero-br{grid-row:3;grid-column:2;justify-self:end;align-self:end;}
  .pp-play{background:transparent;border:1px solid var(--fg);color:var(--fg);
    padding:14px 22px;cursor:pointer;letter-spacing:.18em;
    transition:background .2s, color .2s, border-color .2s;}
  .pp-play:hover{background:var(--accent);border-color:var(--accent);color:#0a0908;}

  .pp-syn{display:grid;grid-template-columns:1.2fr 1fr;gap:96px;padding:96px 56px;
    border-bottom:1px solid var(--line);}
  .pp-syn-l{display:flex;flex-direction:column;gap:18px;max-width:48ch;}
  .pp-syn-text{font-size:32px;line-height:1.18;margin:0;}
  .pp-syn-r{display:flex;flex-direction:column;gap:14px;}
  .pp-credits{width:100%;border-collapse:collapse;}
  /* Credits table rows are a list, so their hairlines follow the
     admin's WORKS-LIST HAIRLINE OPACITY setting (via --line-projects).
     Structural hairlines on .pp-hd / .pp-ft / hero stay on the fixed
     --line value. */
  .pp-credits th, .pp-credits td{text-align:left;padding:12px 0;
    border-bottom:1px solid var(--line-projects);font-weight:400;}
  .pp-credits th{width:38%;}

  .pp-gal{padding:0 56px;display:flex;flex-direction:column;gap:24px;margin-top:24px;}
  .pp-gal-tail{padding:48px 56px 0;}
  .pp-gal-row{display:grid;}
  .pp-gal-full .imgbox{aspect-ratio:16/9;}
  .pp-gal-2{grid-template-columns:1.4fr 1fr;gap:24px;}
  .pp-gal-2 .pp-gal-tall .imgbox{aspect-ratio:3/4;height:100%;}
  .pp-gal-2 .pp-gal-stack{display:flex;flex-direction:column;gap:10px;}
  .pp-gal-2 .pp-gal-stack .imgbox{aspect-ratio:5/4;}
  .pp-cap{display:flex;justify-content:space-between;}
  .pp-gal-strip{grid-template-columns:repeat(4,1fr);gap:14px;}
  .pp-gal-strip .imgbox{aspect-ratio:4/5;}

  /* Clickable still wrapper. The button is a transparent layout host
     so all descendant `.pp-* .imgbox{aspect-ratio:…}` rules still match
     through it; only the cursor + a subtle hover lift signal that the
     image opens fullscreen. */
  .pp-still{display:block;width:100%;height:100%;
    padding:0;margin:0;background:transparent;border:0;color:inherit;
    font:inherit;text-align:inherit;cursor:zoom-in;}
  .pp-still .imgbox{transition:filter .25s ease;}
  .pp-still:hover .imgbox{filter:brightness(1.06);}
  .pp-still:focus-visible{outline:1px solid var(--accent);outline-offset:4px;}

  /* Lightbox: fixed full-viewport overlay, image fit to viewport. The
     body scroll is locked while open (JS toggles overflow:hidden) so
     mobile pinch-zoom stays anchored to the lightbox image. */
  .pp-lightbox{position:fixed;inset:0;z-index:100;
    background:rgba(10,8,7,.96);
    display:flex;align-items:center;justify-content:center;
    padding:48px;cursor:zoom-out;
    animation:nv-fade-in .18s ease-out both;}
  .pp-lightbox-img{display:block;max-width:100%;max-height:100%;
    object-fit:contain;cursor:default;}
  .pp-lightbox-close{position:absolute;top:24px;right:24px;
    background:transparent;border:1px solid var(--line);color:var(--fg);
    padding:8px 14px;cursor:pointer;
    transition:background .2s, color .2s, border-color .2s;}
  .pp-lightbox-close:hover{background:var(--accent);border-color:var(--accent);color:#0a0908;}

  .pp-pull{display:grid;grid-template-columns:auto 1fr auto;gap:32px;align-items:center;
    padding:120px 56px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);
    margin-top:96px;}
  .pp-pull-mark{font-family:var(--serif);font-size:200px;line-height:.6;align-self:start;
    margin-top:-12px;}
  .pp-pull-text{font-size:48px;line-height:1.12;margin:0;max-width:24ch;}
  .pp-pull-attr{align-self:end;}

  .pp-specs{display:grid;grid-template-columns:repeat(6,1fr);gap:0;
    padding:32px 56px;border-bottom:1px solid var(--line);}
  .pp-spec{display:flex;flex-direction:column;gap:6px;padding:0 12px 0 0;
    border-right:1px solid var(--line);}
  .pp-spec:last-child{border-right:0;}

  .pp-next{position:relative;display:block;height:64vh;min-height:480px;color:var(--fg);}
  .pp-next-img{position:absolute;inset:0;}
  .pp-next-img .imgbox{height:100%;border:0;}
  .pp-next-overlay{position:absolute;inset:0;display:flex;flex-direction:column;
    align-items:center;justify-content:center;gap:18px;text-align:center;}
  .pp-next-name{font-size:clamp(56px,7vw,108px);line-height:.9;letter-spacing:-.01em;
    transition:color .25s;}
  .pp-next:hover .pp-next-name{color:var(--accent);}

  /* Project/Studio/Contact page footer — same hairline + rhythm as
     .ab.v2 > .ft, now in-flow so it scrolls with the page. The
     selector also covers the bare <Footer /> emitted directly into
     the project page (no .pp-ft class), where the second declaration
     block applies. */
  .pp-ft, .pp > footer.ft{
    border-top:1px solid var(--line);
    padding-top:clamp(14px, 1.7vh, 22px);
    padding-bottom:clamp(14px, 1.7vh, 22px);
    padding-left:var(--bar-inset);padding-right:var(--bar-inset);
    margin:0;
    line-height:1;
    display:flex;align-items:center;justify-content:space-between;}

  /* nav active state on subpages */
  .hd-nav a.is-here{color:var(--accent);}

  /* ── Studio page ───────────────────────────────────────────────── */
  .st-intro{padding:120px 56px 72px;display:flex;flex-direction:column;gap:28px;
    border-bottom:1px solid var(--line);}
  .st-mani{font-size:clamp(72px,10vw,180px);line-height:.86;letter-spacing:-.02em;
    margin:0;max-width:18ch;}
  .st-lede{font-size:24px;line-height:1.3;margin:0;max-width:46ch;color:var(--fg);}

  .st-portrait{padding:48px 56px 24px;display:flex;flex-direction:column;gap:10px;}
  .st-portrait .imgbox{aspect-ratio:21/9;}
  .st-portrait-cap{display:flex;justify-content:space-between;}

  .st-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:96px;padding:96px 56px;
    border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-top:48px;}
  .st-col{display:flex;flex-direction:column;gap:18px;}
  .st-approach{font-size:20px;line-height:1.4;margin:0;max-width:46ch;}

  .st-team{padding:96px 56px;border-bottom:1px solid var(--line);
    display:flex;flex-direction:column;gap:32px;}
  .st-team-list{list-style:none;padding:0;margin:0;
    display:grid;grid-template-columns:repeat(2,1fr);gap:0 64px;}
  .st-team-list li{display:flex;justify-content:space-between;align-items:baseline;
    padding:18px 0;border-top:1px solid var(--line);}
  .st-team-list li:last-child, .st-team-list li:nth-last-child(2){border-bottom:none;}
  .st-team-name{font-size:32px;line-height:1;letter-spacing:.01em;}

  .st-clients{padding:96px 56px;border-bottom:1px solid var(--line);
    display:flex;flex-direction:column;gap:32px;}
  .st-clients-grid{list-style:none;padding:0;margin:0;
    display:grid;grid-template-columns:repeat(4,1fr);gap:14px 24px;}
  .st-clients-grid li{padding:14px 0;border-top:1px solid var(--line);
    letter-spacing:.18em;}

  .st-press{padding:96px 56px;border-bottom:1px solid var(--line);
    display:flex;flex-direction:column;gap:32px;}
  .st-press-tbl{width:100%;border-collapse:collapse;}
  .st-press-tbl td{padding:18px 0;border-top:1px solid var(--line);
    vertical-align:baseline;font-size:22px;line-height:1.2;}
  .st-press-src{width:18%;letter-spacing:.18em;}
  .st-press-yr{width:14%;text-align:right;letter-spacing:.18em;}

  /* Legal / registration info — same rhythm as st-team rows so the
     P.IVA reads as part of the studio's quiet info block. */
  .st-info{padding:96px 56px;border-bottom:1px solid var(--line);
    display:flex;flex-direction:column;gap:24px;}
  .st-info-list{list-style:none;padding:0;margin:0;
    display:flex;flex-direction:column;}
  .st-info-list li{display:flex;justify-content:space-between;align-items:baseline;
    padding:18px 0;border-top:1px solid var(--line);max-width:760px;gap:24px;}
  .st-info-list li:last-child{border-bottom:1px solid var(--line);}
  /* Long values (denominazione, attività) wrap onto a second line —
     right-align so each wrap edge tracks the section's right column
     and label/value never collide. */
  .st-info-list li > span:last-child{text-align:right;}

  .st-cta{padding:140px 56px;display:flex;flex-direction:column;gap:28px;
    align-items:center;text-align:center;border-bottom:1px solid var(--line);}
  .st-cta-text{font-size:clamp(56px,8vw,128px);line-height:.9;letter-spacing:-.01em;
    max-width:18ch;}
  .st-cta-link{color:var(--fg);border-bottom:1px solid var(--fg);padding-bottom:6px;
    letter-spacing:.18em;transition:color .2s, border-color .2s;}
  .st-cta-link:hover{color:var(--accent);border-color:var(--accent);}

  /* ── Contact page ──────────────────────────────────────────────── */
  .ct-hero{padding:120px 56px 72px;display:flex;flex-direction:column;gap:28px;
    border-bottom:1px solid var(--line);}
  .ct-title{font-size:clamp(72px,10vw,180px);line-height:.86;letter-spacing:-.02em;
    margin:0;}
  .ct-lede{font-size:24px;line-height:1.3;margin:0;max-width:46ch;color:var(--fg);}

  .ct-grid{display:grid;grid-template-columns:1fr 1.4fr;gap:96px;
    padding:96px 56px;border-bottom:1px solid var(--line);}
  .ct-col{display:flex;flex-direction:column;gap:18px;}
  .ct-direct{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;}
  .ct-direct li{display:grid;grid-template-columns:140px 1fr;align-items:baseline;
    padding:18px 0;border-top:1px solid var(--line);}
  .ct-direct li:last-child{border-bottom:1px solid var(--line);}
  .ct-link{font-size:24px;color:var(--fg);transition:color .2s;}
  a.ct-link:hover{color:var(--accent);}

  .ct-form{display:grid;grid-template-columns:1fr 1fr;gap:18px 24px;
    align-content:start;}
  .ct-form > span:first-child{grid-column:1 / -1;}
  .ct-field{display:flex;flex-direction:column;gap:8px;}
  .ct-field-wide{grid-column:1 / -1;}
  .ct-field input, .ct-field select, .ct-field textarea{
    background:transparent;border:0;border-bottom:1px solid var(--line);
    color:var(--fg);font:400 18px/1.4 var(--serif);font-style:italic;
    padding:10px 0;outline:none;transition:border-color .2s;}
  .ct-field select{font-style:normal;font-family:var(--mono);font-size:13px;
    letter-spacing:.18em;text-transform:uppercase;}
  .ct-field input:focus, .ct-field select:focus, .ct-field textarea:focus{
    border-color:var(--accent);}
  .ct-field textarea{resize:vertical;min-height:120px;}
  .ct-send{justify-self:start;grid-column:1 / -1;
    background:transparent;border:1px solid var(--fg);color:var(--fg);
    padding:14px 24px;cursor:pointer;letter-spacing:.18em;
    transition:background .2s, color .2s, border-color .2s;}
  .ct-send:hover{background:var(--accent);border-color:var(--accent);color:#0a0908;}

  .ct-locations{display:grid;grid-template-columns:repeat(3,1fr);gap:0;
    border-bottom:1px solid var(--line);}
  .ct-loc{padding:64px 56px;border-right:1px solid var(--line);
    display:flex;flex-direction:column;gap:14px;}
  .ct-loc:last-child{border-right:0;}
  .ct-loc-city{letter-spacing:.18em;}
  .ct-loc-addr{font-size:22px;line-height:1.3;margin:0;white-space:pre-line;}
  .ct-social{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:14px;}
  .ct-social a{color:var(--fg);transition:color .2s;letter-spacing:.18em;}
  .ct-social a:hover{color:var(--accent);}

  /* ── Admin (#/admin) ───────────────────────────────────────────── */
  .adm{background:#0a0908;color:var(--fg);min-height:100vh;width:100%;
    font-family:var(--mono);}
  .adm-hd{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
    padding:18px 28px;border-bottom:1px solid var(--line);
    position:sticky;top:0;background:rgba(10,9,8,.92);backdrop-filter:blur(8px);z-index:10;}
  .adm-back{justify-self:start;color:var(--fg);}
  .adm-back:hover{color:var(--accent);}
  .adm-hd-mid{justify-self:center;color:var(--muted);}
  .adm-hd-r{justify-self:end;display:flex;gap:8px;}
  .adm-mini{background:transparent;border:1px solid var(--line);color:var(--fg);
    font:inherit;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    padding:7px 12px;cursor:pointer;transition:background .18s, border-color .18s, color .18s;}
  .adm-mini:hover{border-color:var(--fg);}
  .adm-mini.adm-del:hover{background:var(--accent);border-color:var(--accent);color:#0a0908;}

  .adm-shell{display:grid;grid-template-columns:340px 1fr;min-height:calc(100vh - 53px);}
  .adm-side{border-right:1px solid var(--line);display:flex;flex-direction:column;
    padding:22px 0;}
  .adm-side-hd{padding:0 24px 16px;font-size:11px;letter-spacing:.18em;}
  .adm-list{list-style:none;margin:0;padding:0;flex:1;overflow:auto;}
  .adm-li{position:relative;}
  .adm-li + .adm-li{border-top:1px solid rgba(241,237,229,.06);}
  .adm-li.is-dragging{opacity:.35;}
  .adm-li.is-over::before{content:"";position:absolute;left:0;right:0;top:-1px;height:2px;
    background:var(--accent);pointer-events:none;}
  .adm-item{width:100%;background:transparent;border:0;color:var(--fg);
    text-align:left;padding:14px 22px 14px 14px;cursor:pointer;display:grid;
    grid-template-columns:26px 36px 1fr 56px;column-gap:12px;align-items:center;
    border-left:3px solid transparent;transition:background .15s, border-color .15s;}
  .adm-grip{display:inline-flex;align-items:center;justify-content:center;
    color:var(--muted);font-family:var(--mono);font-size:18px;letter-spacing:-.08em;
    cursor:grab;user-select:none;opacity:.75;transition:opacity .15s, color .15s;}
  .adm-li:hover .adm-grip{opacity:1;color:var(--fg);}
  .adm-li.is-dragging .adm-grip{cursor:grabbing;color:var(--accent);}
  .adm-item:hover{background:rgba(241,237,229,.05);}
  .adm-item.is-on{background:rgba(241,237,229,.07);border-left-color:var(--accent);}
  .adm-item-name{font-family:var(--display-font);font-size:17px;line-height:1.1;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .adm-new{margin:14px 16px 0;background:transparent;border:1px dashed var(--line);
    color:var(--fg);padding:12px;cursor:pointer;font:inherit;
    font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    transition:background .18s, border-color .18s;}
  .adm-new:hover{border-color:var(--accent);background:rgba(232,68,60,.06);}

  .adm-empty{display:flex;align-items:center;justify-content:center;}
  .adm-main{padding:24px 32px 80px;display:flex;flex-direction:column;gap:18px;}
  .adm-toolbar{display:flex;align-items:center;gap:10px;
    padding:12px 14px;border:1px solid var(--line);
    position:sticky;top:60px;background:rgba(10,9,8,.92);backdrop-filter:blur(8px);z-index:5;}
  .adm-toolbar > span:nth-child(2){font-family:var(--display-font);font-size:18px;}
  .adm-spacer{flex:1;}
  .adm-save{background:transparent;border:1px solid var(--fg);color:var(--fg);
    font:inherit;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    padding:9px 16px;cursor:pointer;transition:background .18s, color .18s;}
  .adm-save.is-dirty{background:var(--accent);border-color:var(--accent);color:#0a0908;}
  .adm-save:disabled{opacity:.45;cursor:default;}

  .adm-sec{border:1px solid var(--line);}
  .adm-sec-hd{display:flex;justify-content:space-between;align-items:baseline;
    padding:12px 16px;border-bottom:1px solid var(--line);background:rgba(241,237,229,.02);}
  .adm-sec-body{padding:16px;display:flex;flex-direction:column;gap:14px;}

  .adm-row-flex{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;}
  .adm-row-flex .adm-field{min-width:0;}
  .adm-field{display:flex;flex-direction:column;gap:6px;}
  .adm-field.is-short{max-width:160px;}
  .adm-inp{background:#16140f;border:1px solid var(--line);color:var(--fg);
    font:400 14px/1.4 var(--serif);padding:10px 12px;outline:none;
    transition:border-color .18s;}
  .adm-inp.adm-mono{font:inherit;font-size:12px;letter-spacing:.04em;}
  .adm-inp:focus{border-color:var(--accent);}
  textarea.adm-inp{resize:vertical;min-height:60px;}
  .adm-field.is-error .adm-inp{border-color:var(--accent);}
  .adm-hint{display:block;line-height:1.4;}
  .adm-hint-err{color:var(--accent);}

  .adm-rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;}
  .adm-row{display:grid;grid-template-columns:160px 1fr 32px;gap:8px;align-items:center;}
  .adm-row-still{grid-template-columns:24px 1fr 160px 32px;}
  .adm-still-idx{justify-self:center;}
  .adm-tone{font-size:11px;}
  .adm-x{background:transparent;border:1px solid var(--line);color:var(--muted);
    width:32px;height:32px;cursor:pointer;font-size:18px;line-height:1;
    transition:color .18s, border-color .18s;}
  .adm-x:hover{color:var(--accent);border-color:var(--accent);}
  .adm-add{align-self:start;background:transparent;border:1px dashed var(--line);
    color:var(--muted);padding:8px 12px;cursor:pointer;font:inherit;
    font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    transition:color .18s, border-color .18s;}
  .adm-add:hover{color:var(--fg);border-color:var(--fg);}

  .adm-toggle{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:center;
    padding:8px 0;cursor:pointer;}
  .adm-toggle.is-disabled{opacity:.4;cursor:not-allowed;}
  .adm-tg{width:42px;height:22px;border:1px solid var(--line);background:#16140f;
    border-radius:999px;position:relative;transition:background .2s, border-color .2s;}
  .adm-tg-dot{position:absolute;top:2px;left:2px;width:16px;height:16px;
    border-radius:50%;background:var(--fg);transition:left .18s, background .18s;}
  .adm-tg.is-on{background:var(--accent);border-color:var(--accent);}
  .adm-tg.is-on .adm-tg-dot{left:22px;background:#0a0908;}
  .adm-toggle-text{display:flex;flex-direction:column;gap:2px;}

  .adm-foot{display:flex;justify-content:flex-end;padding:8px 0;}

  /* ── Vimeo iframe in project hero ──────────────────────────────── */
  /* Responsive Vimeo follows the player's own share-embed snippet:
     the holder is `position:relative` with a `padding-top` equal to
     the source's height/width ratio so it scales with the viewport
     width and the iframe (absolute, inset:0) fills it edge-to-edge.
     padding-top is set inline from oEmbed-fetched dimensions in
     project-page.jsx; the 56.25% fallback below covers the gap
     before the fetch resolves (or if it fails — covers most 16:9
     reels). Background is black so any uncovered area reads as a
     cinematic letterbox rather than the page's off-white. */
  .pp-hero:has(.pp-hero-vimeo){
    height:auto;min-height:0;display:block;background:#000;
    overflow:hidden;
  }
  .pp-hero-img:has(.pp-hero-vimeo){
    position:relative;inset:auto;
    width:100%;height:auto;min-height:0;
    padding-top:56.25%;
    background:#000;overflow:hidden;
  }
  /* The iframe is nudged 1px outside the holder on every side so any
     sub-pixel rounding seam at the edges shows the holder's black
     background underneath instead of the off-white `var(--line)`
     hairline that `.imgbox` carries elsewhere on the page. */
  .pp-hero-vimeo{position:absolute;inset:-1px;width:calc(100% + 2px);height:calc(100% + 2px);
    border:0;background:#000;display:block;}

  /* When the hero is showing a video, the overlay can't overlay the
     iframe (its height is now driven by the video's aspect, so the
     title/credits stretch past the player onto the body below).
     Drop the absolute corner-grid and let the overlay flow as a
     normal block below the video — same metadata, just stacked. */
  .pp-hero:has(.pp-hero-vimeo) .pp-hero-overlay{
    position:relative;inset:auto;
    grid-template-columns:1fr auto;
    grid-template-rows:auto auto;
    row-gap:18px;column-gap:24px;
    padding:32px 56px 40px;
    background:var(--bg);
    border-bottom:1px solid var(--line);
    pointer-events:auto;
  }
  .pp-hero:has(.pp-hero-vimeo) .pp-hero-tl{grid-row:1;grid-column:1;}
  .pp-hero:has(.pp-hero-vimeo) .pp-hero-tr{grid-row:1;grid-column:2;justify-self:end;}
  .pp-hero:has(.pp-hero-vimeo) .pp-hero-bl{
    grid-row:2;grid-column:1 / -1;align-self:start;max-width:none;}
  .pp-hero:has(.pp-hero-vimeo) .pp-hero-br{display:none;}

  /* Autoplay video chrome — tap-to-toggle layer + mute + fullscreen.
     All three only render when proj.autoplay is on; the WATCH FILM
     path keeps Vimeo's own chrome (which already includes pause,
     mute, fullscreen). The tap layer fills the iframe area at
     z-index 3 so clicks pause/resume via the player SDK; the corner
     buttons sit at z-index 5 so they keep receiving clicks. */
  .pp-hero-tap{
    position:absolute;inset:0;z-index:3;
    background:transparent;border:0;padding:0;margin:0;cursor:pointer;
  }
  .pp-hero-tap:focus{outline:none;}
  .pp-hero-mute, .pp-hero-fs{
    position:absolute;bottom:18px;z-index:5;
    width:40px;height:40px;padding:0;
    display:inline-flex;align-items:center;justify-content:center;
    color:#fff;background:transparent;border:0;cursor:pointer;
    line-height:1;
    filter:drop-shadow(0 1px 3px rgba(0,0,0,.65));
    transition:opacity .15s;
  }
  .pp-hero-mute:hover, .pp-hero-fs:hover{opacity:.7;}
  .pp-hero-mute svg, .pp-hero-fs svg{display:block;}
  /* Desktop: both controls clustered bottom-right, fullscreen sits
     immediately to the left of the mute toggle. */
  .pp-hero-mute{right:18px;}
  .pp-hero-fs{right:62px;}

  /* Hero still veil: covers the iframe while Vimeo's gray loader is
     still painting. Removed from DOM as soon as the player reports
     it's playing. Pure black background under the image — and the
     image holder itself drops the site-wide `.imgbox` 1px line
     (a `rgba(fg, .18)` cream hairline) so no off-white edge can
     bleed through under the video. */
  .pp-hero-veil{
    position:absolute;inset:0;z-index:2;
    pointer-events:none;background:#000;overflow:hidden;
  }
  .pp-hero-veil .imgbox{
    width:100%;height:100%;
    border:0 !important;background:#000;
  }
  .pp-hero-veil .imgbox img{background:#000;}

  /* ── Admin: per-section toggles ────────────────────────────────── */
  .adm-sec-hd{align-items:center;gap:14px;}
  .adm-sec-hd-l{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1;}
  .adm-sec-tg{background:transparent;border:1px solid var(--line);color:var(--fg);
    font:inherit;font-size:10px;letter-spacing:.16em;text-transform:uppercase;
    padding:5px 10px;cursor:pointer;display:inline-flex;align-items:center;gap:10px;
    transition:border-color .18s, color .18s;}
  .adm-sec-tg:hover{border-color:var(--fg);}
  .adm-sec-tg .adm-tg-sm{width:30px;height:16px;border:1px solid var(--line);
    background:#16140f;border-radius:999px;position:relative;
    transition:background .2s, border-color .2s;}
  .adm-sec-tg .adm-tg-sm .adm-tg-dot{position:absolute;top:1px;left:1px;width:12px;height:12px;
    border-radius:50%;background:var(--fg);transition:left .18s, background .18s;}
  .adm-sec-tg .adm-tg-sm[data-on]{background:var(--accent);border-color:var(--accent);}
  .adm-sec-tg .adm-tg-sm[data-on] .adm-tg-dot{left:15px;background:#0a0908;}
  .adm-sec-tg:has(.adm-tg-sm:not([data-on])){color:var(--muted);}
  .adm-sec.is-off{opacity:.55;}
  .adm-sec.is-off .adm-sec-body{filter:grayscale(.4);}

  /* ══════════════════════════════════════════════════════════════════
     RESPONSIVE — tablet ≤1100, mobile ≤768, small mobile ≤480
     ══════════════════════════════════════════════════════════════════ */
  @media (max-width: 1100px){
    .ab{padding:32px 32px 28px;}
    .v3{grid-template-columns:1fr;}
    .v3-left{border-right:0;border-bottom:1px solid var(--line);}
    .v4-grid{grid-template-columns:1fr;gap:32px;}
    .v7-body{grid-template-columns:1fr;}
    .v9{padding:36px 36px 32px;}
    .v9-row{grid-template-columns:1fr;gap:32px;}
    /* V2 — stack: seal sits on its own row, centered, above the list.
       Pin the wordmark's distance-from-top to the values that apply right at
       1100px so it stays anchored at the same pixel offset across the
       breakpoint and on every smaller viewport. */
    /* padding-top:0 — the sticky .hd owns its top breathing space (see
       the .ab.v2 > .hd rule on desktop). Bottom is 0 because the
       in-flow footer carries its own padding. */
    .ab.v2{padding-top:0;padding-bottom:0;}
    /* Tighter framing on phones — hairlines stay but the gaps shrink. */
    .ab.v2 > .hd{padding-bottom:13px;}
    .ab.v2 > .ft{padding-top:14px;padding-bottom:18px;}
    /* Stack the wordmark and the seal — wordmark full width on top, seal
       below, sized noticeably larger than its desktop cousin and tucked
       close to the wordmark's baseline instead of sitting in a separate
       row. margin-top is a fixed pixel value so the gap to the topbar
       hairline stays the same on every device, not viewport-relative. */
    .v2-mark{flex-direction:column;align-items:center;justify-content:center;
      gap:0;width:100%;align-self:stretch;
      margin-top:24px;margin-bottom:0;}
    /* Match the works list width — both occupy 100% of .v2-mark, which
       is the artboard's content area (viewport − 2 × bar-inset). */
    .v2-wordmark{flex:0 0 auto;width:100%;max-width:100%;
      margin-left:0;margin-right:0;}
    .v2-mark > .v2-seal{flex:0 0 auto;width:clamp(124px, 20.8vw, 207px);max-width:none;
      justify-content:center;align-items:center;
      /* Wordmark viewBox now ends exactly at the baseline, so the seal
         sits directly under the visible glyphs with a flat pixel gap —
         no proportional negative margin needed anymore. */
      margin-top:16px;}
    /* Reset the desktop -50px nudge that pushes the seal into the
       wordmark column — on mobile the seal is centred under the
       wordmark and the offset would push it off to the left. */
    .v2-mark > .v2-seal .v2-seal-mark{width:100%;height:auto;aspect-ratio:1;
      margin-left:0;}
    .v2-bottom{display:block;margin-top:14px;}
    .v2-bottom .v2-list{flex:0 0 auto;width:100%;max-width:100%;}

    .pp-hd, .pp-pull, .pp-specs, .pp-ft,
    .pp-syn, .pp-gal, .pp-gal-tail{padding-left:32px;padding-right:32px;}
    .pp-syn{grid-template-columns:1fr;gap:48px;padding-top:64px;padding-bottom:64px;}
    .pp-pull{padding-top:80px;padding-bottom:80px;margin-top:64px;}
    .pp-specs{grid-template-columns:repeat(3,1fr);row-gap:18px;}
    .pp-spec:nth-child(3n){border-right:0;}

    .st-intro, .st-grid, .st-team, .st-clients, .st-press, .st-info, .st-cta,
    .st-portrait{padding-left:32px;padding-right:32px;}
    .st-grid{grid-template-columns:1fr;gap:48px;}
    .st-team-list{grid-template-columns:1fr;}
    .st-clients-grid{grid-template-columns:repeat(3,1fr);}

    .ct-hero, .ct-grid{padding-left:32px;padding-right:32px;}
    .ct-grid{grid-template-columns:1fr;gap:48px;}
    .ct-locations{grid-template-columns:1fr;}
    .ct-loc{border-right:0;border-bottom:1px solid var(--line);padding:48px 32px;}
    .ct-loc:last-child{border-bottom:0;}
  }

  @media (max-width: 768px){
    /* Generic shell */
    html,body{overflow-x:hidden;}
    .root-stage>.ab{min-height:auto;}
    .ab{padding:20px 18px 24px;min-height:auto;}
    .hd{flex-wrap:wrap;gap:14px;}
    .hd-nav{gap:18px;}
    .hd-mid{display:none;}
    /* Allow the footer to wrap on phones: with the social labels
       expanded to INSTAGRAM/VIMEO/BEHANCE the line can overflow the
       viewport (and would otherwise get clipped by html,body's
       overflow-x:hidden). margin-left:auto on .ft-right keeps the
       social cluster right-aligned both before and after wrapping. */
    .ft{gap:8px;flex-wrap:wrap;row-gap:8px;}
    .ft-right{gap:18px;margin-left:auto;}

    /* V2 home — fluid type handled by clamp() above; only layout swaps here */
    .v2-panel{display:none;} /* hide tweaks/control panel on phones */
    .v2-list-head{display:none;}
    .v2-list-row{grid-template-columns:32px 1fr 56px;gap:12px;
      grid-template-areas:"n name yr" "n meta yr";row-gap:2px;padding:10px 0;}
    .v2-list-row > span:nth-child(1){grid-area:n;align-self:start;}
    .v2-list-row > span:nth-child(2){grid-area:name;}
    .v2-list-row > span:nth-child(3){grid-area:meta;font-size:10px;}
    .v2-list-row > span:nth-child(4){grid-area:yr;justify-self:end;}
    /* On mobile the works list is full-width: there's no "expand the
       table left" trick. Long names must wrap onto a second line
       rather than overflow the viewport. Override the desktop's
       white-space:nowrap and let names break wherever needed. Size
       is auto-scaled to 80% of the admin-chosen --projects-size so
       phones don't get the desktop's full-bleed letter sizes. */
    .v2-list-name{font-size:calc(var(--projects-size, 20px) * 0.8);white-space:normal;overflow-wrap:anywhere;line-height:1.05;}
    /* On narrow viewports the preview grid drops to 2 columns. The
       preview is no longer suppressed on touch — tap-to-reveal /
       tap-again-to-open is handled in JS. */
    .v2-list-preview-inner{grid-template-columns:repeat(2,minmax(0,1fr));}

    /* Project page */
    .pp-hd{padding:14px 18px;grid-template-columns:auto 1fr;gap:12px;}
    .pp-hd-mid{display:none;}
    .pp-hd .hd-nav{justify-self:end;gap:14px;font-size:10px;}
    .pp-hero{height:auto;min-height:0;display:flex;flex-direction:column;}
    .pp-hero-img{position:relative;inset:auto;height:62vh;min-height:380px;}
    .pp-hero-overlay{position:relative;inset:auto;display:flex;flex-direction:column;gap:18px;
      padding:24px 18px 32px;background:var(--bg);border-bottom:1px solid var(--line);}
    .pp-hero-tl, .pp-hero-tr, .pp-hero-bl, .pp-hero-br{
      grid-row:auto;grid-column:auto;justify-self:auto;align-self:auto;}
    .pp-hero-tr{flex-wrap:wrap;}
    /* Video-overlay: drop the desktop's 2-row grid (defined outside
       this @media) and use the same flex-column stack with mobile
       padding. Same specificity as the desktop :has() rule but later
       in source order — wins inside this breakpoint. */
    .pp-hero:has(.pp-hero-vimeo) .pp-hero-overlay{
      display:flex;flex-direction:column;
      padding:24px 18px 32px;
    }
    /* Tighter inset on small screens; fullscreen flips to the
       opposite (left) corner so the two thumb targets don't pile
       on top of each other at phone widths. */
    .pp-hero-mute{bottom:10px;right:10px;}
    .pp-hero-fs{bottom:10px;right:auto;left:10px;}
    /* Project page hero title on tablet/mobile (≤768): 70% of the
       previous 48px size, and allowed to wrap onto multiple lines
       when the name is too long for one line at this width. */
    .pp-title{font-size:34px;white-space:normal;overflow-wrap:anywhere;line-height:.95;}
    .pp-tagline{font-size:18px;}
    .pp-syn, .pp-gal, .pp-gal-tail, .pp-pull, .pp-specs, .pp-ft{
      padding-left:18px;padding-right:18px;}
    .pp-syn{padding-top:48px;padding-bottom:48px;gap:32px;}
    .pp-syn-text{font-size:22px;}
    .pp-gal{margin-top:0;gap:14px;}
    .pp-gal-2{grid-template-columns:1fr;gap:14px;}
    .pp-gal-2 .pp-gal-tall .imgbox{aspect-ratio:4/3;}
    .pp-gal-strip{grid-template-columns:repeat(2,1fr);gap:10px;}
    .pp-gal-tail{padding-top:24px;}
    .pp-pull{grid-template-columns:1fr;gap:14px;padding:64px 18px;margin-top:48px;}
    .pp-pull-mark{font-size:120px;margin-top:-8px;line-height:.5;}
    .pp-pull-text{font-size:28px;}
    .pp-specs{grid-template-columns:repeat(2,1fr);row-gap:14px;padding:24px 18px;}
    .pp-spec{border-right:0;}
    .pp-spec:nth-child(odd){border-right:1px solid var(--line);}
    .pp-next{height:42vh;min-height:300px;}
    .pp-next-name{font-size:42px;}
    .pp-ft{padding:18px;}
    /* Tighten lightbox margins on phones so the image gets all the
       viewport it can; close button shrinks to a 32px-square chip. */
    .pp-lightbox{padding:18px;}
    .pp-lightbox-close{top:14px;right:14px;padding:6px 10px;font-size:10px;}

    /* Studio */
    .st-intro, .st-cta{padding:64px 18px 48px;}
    .st-mani{font-size:48px;}
    .st-lede, .st-approach{font-size:18px;}
    .st-portrait{padding:24px 18px 12px;}
    .st-portrait .imgbox{aspect-ratio:4/3;}
    .st-grid, .st-team, .st-clients, .st-press, .st-info{padding:64px 18px;gap:24px;}
    .st-team-name{font-size:22px;}
    .st-clients-grid{grid-template-columns:repeat(2,1fr);}
    .st-press-tbl td{font-size:16px;padding:14px 0;}
    .st-press-src, .st-press-yr{width:auto;}
    .st-cta-text{font-size:42px;}

    /* Contact */
    .ct-hero{padding:64px 18px 48px;}
    .ct-title{font-size:48px;}
    .ct-lede{font-size:18px;}
    .ct-grid{padding:48px 18px;gap:32px;}
    .ct-direct li{grid-template-columns:1fr;gap:6px;}
    .ct-link{font-size:18px;}
    .ct-form{grid-template-columns:1fr;}
    .ct-loc{padding:32px 18px;}
    .ct-loc-addr{font-size:18px;}

    /* Variants we keep but compact */
    .v3-feat, .v4-feat-name, .v6-pname, .v9-mark text{font-size:64px !important;}
    .v3-list li, .v6-projlist li, .v9-row-item{
      grid-template-columns:auto 1fr auto;column-gap:14px;}
    .v9-row-item{font-size:9px;letter-spacing:.12em;padding:14px 0;}
    .v9-row-item .v9-pn{font-size:22px;}
    .v9-row-item > *:nth-child(4),
    .v9-row-item > *:nth-child(5){display:none;}
    .v5-thumbs{grid-template-columns:repeat(2,1fr);height:auto;}
    .v5-row{grid-template-columns:1fr;gap:24px;}
    .v8{padding:20px 18px;}
    .v8-mark{font-size:8px;}
    .v8-table{font-size:11px;}
    .v8-table th,.v8-table td{padding:8px 6px;}
  }

  @media (max-width: 480px){
    .ab{padding:18px 14px 20px;}
    /* Small mobile (≤480): same 70% scale applied to the previous 36px. */
    .pp-title{font-size:25px;}
    .pp-syn-text{font-size:18px;}
    .pp-pull-text{font-size:22px;}
    .pp-next-name{font-size:32px;}
    .st-mani, .ct-title{font-size:36px;}
    /* V2 fluid scale handled by clamp() — nothing extra needed here */
  }
