/*
 * Ginalca theme — main stylesheet.
 * (The theme root style.css only holds the required WordPress theme
 * header comment; all actual rules live here for easier editing.)
 */

/* =========================================================
   0. Reset & Design Tokens
========================================================= */
:root{
  --ink:#0e0e0e;--ink-2:#2a2a2a;--gray:#8d8d8d;--gray-2:#b6b6b6;
  --line:#e9e9e9;--line-2:#f2f2f2;--paper:#fff;--paper-2:#fafafa;--paper-3:#f4f4f4;
  --r:18px;--ease:cubic-bezier(.76,0,.24,1);
  --serif:"Times New Roman","Hiragino Mincho ProN",serif;
  --sans:"Helvetica Neue","Hiragino Sans","Hiragino Kaku Gothic ProN","Noto Sans JP",system-ui,sans-serif;
  --wrap:1180px;
  --pad:24px;
  --bg-y:0%; /* snapped per swipe-panel by assets/js/main.js — see .site-bg */
  --header-h:64px; /* fallback; assets/js/main.js measures the real .site-header
                       height (taller on TAB/SP once .primary-nav-sub is added)
                       and overwrites this on load/resize. */
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html{scroll-behavior:smooth;}
/* Client report: in-page anchor links (e.g. the Blog TOC's #見出しid
   links) land with the target hidden behind .site-header, since it's
   position:sticky and stays pinned at the top instead of scrolling out
   of the way. scroll-padding-top reserves that much space at the top of
   the scrollport for ANY native anchor jump, so the browser stops short
   instead of scrolling the target flush to the very top. TAB/SP get a
   taller value since .site-header also carries the second
   .primary-nav-sub-row there (<960px) on top of the 64px bar. */
html{scroll-padding-top:130px;}
@media(min-width:960px){
  html{scroll-padding-top:90px;}
}
html.intro-lock{overflow:hidden;} /* suspended while .intro-overlay is up — see main.js */
body{
  font-family:var(--sans);color:var(--ink);background:transparent;
  -webkit-font-smoothing:antialiased;line-height:1.6;
}
/* Client request: on short viewports (landscape phones, small browser
   windows, etc. — height ≤ 700px) scale everything, text included, down
   to 90% in one shot. Every font-size in this stylesheet is a hardcoded
   px value (not rem, relative to the root font-size), so a root
   font-size trick wouldn't cascade to any of them — zoom is the one CSS
   property that uniformly rescales an entire subtree (text, spacing,
   layout — everything) without editing each rule individually. Widely
   supported across current Chrome/Edge/Safari/Firefox. */
@media (max-height:700px){
  html{zoom:0.9;}
}
/* Service/Contents/Contact sit every-other page in the swipe sequence
   (Top → Service → Works → Contents → Company → Contact) — a faint tint
   here (still shows the .site-bg pattern through it, since that layer's
   own opacity is separate) differentiates them from their plain-white
   neighbors (Top/Works/Company) as you move through the sequence.
   Client request: all 5 tints temporarily disabled (all pages plain white
   like Top, no color distinction) — may be restored later. Original values
   kept in this comment for easy revert:
   service:#fbfdff / works:#fffdf8 / contents:#f8faff / contact:#fafafa /
   company:#fffdfd */
body.swipe-key-service,
body.swipe-key-works,
body.swipe-key-contents,
body.swipe-key-contact,
body.swipe-key-company{
  background:#fff;
}
img{max-width:100%;display:block;}
a{color:inherit;}
ul,ol{list-style:none;}
button{font-family:inherit;}
.container{max-width:var(--wrap);margin:0 auto;padding:0 var(--pad);}
.skip-link{position:absolute;left:-9999px;top:0;background:#fff;color:#111;padding:12px 18px;z-index:9999;}
.skip-link:focus{left:12px;top:12px;}

/* type helpers */
.eyebrow{font-family:var(--serif);font-size:11px;letter-spacing:.32em;color:var(--gray);text-transform:uppercase;display:flex;align-items:center;gap:10px;margin-bottom:18px;}
.eyebrow::before{content:"";width:26px;height:1px;background:currentColor;}
/* Client request: TOP's What we are / What we do labels moved from
   pattern D (outline pill) to pattern "B. サイズ拡大＋下線" from the
   label options shown earlier — its own class so no other .eyebrow
   usage sitewide is affected. Keeps the SP/TAB/PC responsive sizing
   from the prior request. */
.section-label{display:inline-block;font-family:var(--serif);font-size:14px;letter-spacing:.22em;color:var(--ink);text-transform:uppercase;border-bottom:1px solid var(--ink);padding-bottom:9px;margin-bottom:18px;}
@media(max-width:700px){
  .section-label{font-size:12px;padding-bottom:8px;}
}
@media(min-width:960px){
  .section-label{font-size:16px;padding-bottom:10px;}
}
.kicker{font-family:var(--serif);font-size:10px;letter-spacing:.26em;color:var(--gray);text-transform:uppercase;margin-bottom:12px;}
h1,h2,h3{font-weight:400;}
.title{font-family:var(--serif);font-size:32px;line-height:1.3;letter-spacing:.02em;margin:6px 0 20px;}
h3.big{font-family:var(--serif);font-size:25px;line-height:1.35;margin:4px 0 14px;letter-spacing:.02em;}
.lead{font-size:14.5px;line-height:2.0;color:var(--ink-2);letter-spacing:.02em;}
/* Client request: manual line-break inside the Works archive's intro
   .lead (works-loop.php) is PC/TAB-only — the sentence just wraps
   naturally on its own on narrow SP widths, so the <br> is suppressed
   there instead of forcing an extra-short first line. */
@media(max-width:700px){
  .lead-br{display:none;}
}
.muted{color:var(--gray);}
/* Client request: Service page's "Service 01/02" .muted subtitle
   (page-service.php) gets its own PC size — moved out of that element's
   inline style into this scoped rule so it can vary by breakpoint. */
.service-grid .muted{font-size:12px;letter-spacing:.1em;}
@media(min-width:960px){
  .service-grid .muted{font-size:14px;}
}
.tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px;}
.tags span{font-size:11px;letter-spacing:.08em;color:var(--ink-2);border:1px solid var(--line);border-radius:40px;padding:6px 13px;}
/* .br-pc — a manual line break meant for PC/tablet layouts only; collapses
   away on phones so the text just wraps naturally there instead. */
@media(max-width:700px){.br-pc{display:none;}}

@media(min-width:960px){
  .title{font-size:42px;}
  h3.big{font-size:30px;}
  .lead{font-size:15.5px;}
}
/* Client request: Service page's "Service 01/02" h2.title gets its own
   size/margin-bottom (see .service-grid .muted above for the same
   scoping pattern) — moved out of that element's inline style so it can
   vary by breakpoint; the FV h1.title above it still just uses the
   plain .title rules with no page-specific override. */
.service-grid .title{font-size:28px;}
@media(min-width:960px){
  .service-grid .title{font-size:34px;margin-bottom:10px;}
}

/* =========================================================
   1. Header / Nav
========================================================= */
.site-header{
  position:sticky;top:0;left:0;right:0;z-index:200;
  background:rgba(255,255,255,.92);backdrop-filter:saturate(140%) blur(10px);
  border-bottom:1px solid var(--line-2);
}
.site-header .container{display:flex;align-items:center;justify-content:space-between;height:64px;}
.brand{display:flex;align-items:center;text-decoration:none;}
.brand-logo{display:block;height:30px;width:auto;}
.primary-nav{display:none;}
.primary-nav ul{display:flex;gap:2px;align-items:center;}
.primary-nav a{
  position:relative;display:block;padding:10px 16px;font-family:var(--serif);font-size:13px;letter-spacing:.12em;
  text-decoration:none;color:var(--ink-2);transition:.25s;
}
.primary-nav a:hover,
.primary-nav .current-menu-item > a,
.primary-nav .current-menu-parent > a,
.primary-nav .current-menu-ancestor > a{color:var(--ink);}
.primary-nav .current-menu-item > a::after,
.primary-nav .current-menu-parent > a::after,
.primary-nav .current-menu-ancestor > a::after{
  content:"";position:absolute;left:16px;right:16px;bottom:6px;height:1px;background:var(--ink);
}
.header-cta{display:none;}
.header-cta a{
  font-family:var(--serif);font-size:12.5px;letter-spacing:.1em;color:#fff;background:var(--ink);
  border-radius:40px;padding:10px 20px;text-decoration:none;white-space:nowrap;
}
.menu-btn{width:34px;height:34px;display:flex;flex-direction:column;gap:5px;align-items:center;justify-content:center;cursor:pointer;background:none;border:none;}
.menu-btn span{width:20px;height:1.5px;background:var(--ink);transition:.3s;}
.menu-btn.on span:nth-child(1){transform:translateY(6.5px) rotate(45deg);}
.menu-btn.on span:nth-child(2){opacity:0;}
.menu-btn.on span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg);}

/* TAB/SP only (<960px): a second row directly under the top header bar,
   showing the SAME primary menu as PC (see .primary-nav-sub-row in
   header.php — a second wp_nav_menu() call, not a CSS trick, since it
   needs to sit as its own full-width row below the flex top bar rather
   than squeezed inside it). The top bar itself (.site-header .container)
   is untouched here — hamburger stays at the right edge exactly as
   before. The column prev/next arrows (.navsub-arrow, icon only — no
   label) sit at this row's two ends, but SP only (≤700px) — TAB
   (701–959px) already has room for the original labeled .swipe-arrow
   pair floating near the bottom, so .navsub-arrow stays hidden there to
   avoid showing the same prev/next controls twice. */
.primary-nav-sub-row{display:none;}
.primary-nav-sub{display:none;}
@media(max-width:959.98px){
  .primary-nav-sub-row{
    display:flex;align-items:center;border-top:1px solid var(--line-2);
  }
  .primary-nav-sub{
    display:block;flex:1;min-width:0;
    overflow-x:auto;-webkit-overflow-scrolling:touch;
  }
  .primary-nav-sub::-webkit-scrollbar{display:none;}
  .primary-nav-sub ul{display:flex;gap:2px;padding:6px var(--pad);width:max-content;min-width:100%;}
  .primary-nav-sub a{
    position:relative;display:block;padding:10px 14px;font-family:var(--serif);font-size:12.5px;letter-spacing:.1em;
    text-decoration:none;color:var(--ink-2);white-space:nowrap;
  }
  .primary-nav-sub a:hover,
  .primary-nav-sub .current-menu-item > a,
  .primary-nav-sub .current-menu-parent > a,
  .primary-nav-sub .current-menu-ancestor > a{color:var(--ink);}
  .primary-nav-sub .current-menu-item > a::after,
  .primary-nav-sub .current-menu-parent > a::after,
  .primary-nav-sub .current-menu-ancestor > a::after{
    content:"";position:absolute;left:14px;right:14px;bottom:4px;height:1px;background:var(--ink);
  }
  .navsub-arrow{
    display:none; /* re-enabled at ≤700px (SP) below — hidden here for TAB */
    flex:0 0 auto;align-items:center;justify-content:center;
    width:40px;height:46px;color:var(--ink);text-decoration:none;font-size:15px;
  }
  .navsub-arrow.left{border-right:1px solid var(--line-2);}
  .navsub-arrow.right{border-left:1px solid var(--line-2);}
}
@media(max-width:700px){
  .navsub-arrow{display:flex;}
  /* SP only — TAB (701–959px) keeps the wider, horizontally-scrollable
     version above. On phones the item list should fit one line and
     center, never wrap or scroll; if a label genuinely can't fit (a very
     long menu title on a very narrow phone), it truncates with an
     ellipsis rather than breaking the row. */
  .primary-nav-sub{overflow-x:visible;}
  .primary-nav-sub ul{
    width:100%;min-width:0;justify-content:center;flex-wrap:nowrap;gap:0;
  }
  .primary-nav-sub li{min-width:0;flex:0 1 auto;}
  .primary-nav-sub a{
    padding:8px 8px;font-size:10.5px;letter-spacing:.06em;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  /* Client request: header reads too tall on phones — shrinks both the
     top bar (64px → 52px) and the sub-nav row's own link padding/arrow
     height below it. main.js re-measures the real .site-header height
     into --header-h on load/resize, so every .section's min-height
     (calc(100dvh - var(--header-h))) adjusts to match automatically —
     nothing else needs to change. */
  .site-header .container{height:45px;}
  .brand-logo{height:26px;}
  .navsub-arrow{height:38px;}
}

.mobile-nav{
  position:fixed;inset:0;z-index:190;background:#fff;
  transform:translateY(-100%);transition:transform .5s var(--ease);
  display:flex;flex-direction:column;padding:100px 30px 30px;overflow-y:auto;
}
.mobile-nav.open{transform:translateY(0);}
.mobile-nav ol{flex:1;}
.mobile-nav li{border-bottom:1px solid var(--line);}
.mobile-nav a{display:flex;align-items:baseline;gap:14px;padding:18px 2px;text-decoration:none;color:var(--ink);}
.mobile-nav a .no{font-family:var(--serif);font-size:12px;color:var(--gray);width:24px;}
.mobile-nav a .en{font-family:var(--serif);font-size:24px;letter-spacing:.04em;flex:1;}
.mobile-nav a .ja{font-size:11px;color:var(--gray);letter-spacing:.1em;}
.mobile-nav .foot{font-size:11px;color:var(--gray);letter-spacing:.12em;line-height:1.9;margin-top:20px;}
.mobile-nav .foot em{font-style:italic;}
/* var(--serif) alone won't do it here — its "Times New Roman" comes
   first and already covers every Latin glyph in "Marketing Starts in
   You.", so browsers never fall through to its Mincho fallback for pure
   ASCII text like this. Naming the Mincho fonts directly (no Times New
   Roman ahead of them) is the only way to actually get 明朝体 rendering
   on plain English text. */
.mobile-nav .foot-tagline{font-family:"Hiragino Mincho ProN","Yu Mincho",serif;}
/* SP-only stand-in for the real <footer> (see the display:none override
   for .site-footer at max-width:700px) — same SNS/legal-links/copyright
   content as footer.php's .footer-bottom, restyled for this panel's
   white background instead of the dark .site-footer one. */
.mobile-nav .foot-sns,.mobile-nav .foot-legal{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;}
.mobile-nav .foot-sns a,.mobile-nav .foot-legal a{color:var(--ink-2);text-decoration:none;letter-spacing:.06em;padding-top:0;padding-bottom:0;}
.mobile-nav .foot-sns a:hover,.mobile-nav .foot-legal a:hover{color:var(--ink);text-decoration:underline;}
.mobile-nav .foot-copyright{margin-top:12px;font-size:10px;}
@media(max-width:700px){.mobile-nav .foot-legal{margin-top:0;}}

@media(min-width:960px){
  .primary-nav{display:block;}
  .header-cta{display:block;}
  .menu-btn{display:none;}
}

/* =========================================================
   2. Hero
========================================================= */
.hero{position:relative;overflow:hidden;padding:64px 0 72px;min-height:78vh;display:flex;align-items:center;}
.hero-photo{position:absolute;inset:0;z-index:0;overflow:hidden;}
/* Same pattern/position as .site-bg, rendered without color so the hero
   reads as one continuous piece of artwork with the rest of the page. */
.hero-inner{position:relative;z-index:2;text-align:center;display:flex;flex-direction:column;align-items:center;}
.hero-k{font-family:var(--serif);font-size:12px;letter-spacing:.32em;color:var(--gray);margin-bottom:18px;}
.hero-h1{font-family:var(--serif);font-weight:400;font-size:44px;line-height:1.08;letter-spacing:-.01em;}
.hero-h1 em{font-style:italic;}
.hero-sub{margin-top:20px;font-size:13px;letter-spacing:.14em;color:var(--ink-2);line-height:2;}

.infobox{border:1px solid var(--line);border-radius:14px;background:rgba(255,255,255,.8);backdrop-filter:blur(6px);padding:14px 16px;margin:26px auto 0;max-width:360px;width:100%;text-align:left;}
.infobox .info-h{font-family:var(--serif);font-size:10px;letter-spacing:.26em;color:var(--gray);text-transform:uppercase;margin-bottom:10px;display:flex;align-items:center;gap:8px;}
.infobox .info-h::before{content:"";width:16px;height:1px;background:currentColor;}
.infobox ul{display:flex;flex-direction:column;gap:9px;}
.infobox li a{display:flex;gap:10px;align-items:baseline;text-decoration:none;font-size:12px;line-height:1.4;}
.infobox li .d{font-family:var(--serif);font-size:10px;color:var(--gray);letter-spacing:.05em;flex:0 0 auto;}
.infobox li .t{color:var(--ink-2);}
.infobox li a:hover .t{color:var(--ink);text-decoration:underline;}

/* Information popup (opened by clicking an infobox item — see assets/js/main.js).
   Rendered from footer.php as a true root-level sibling of .site-header/
   .swipe-chrome (not from front-page.php anymore — see the comment there
   and in footer.php), so its z-index:300 now correctly wins against both. */
.newspop{
  position:fixed;inset:0;z-index:300;background:rgba(14,14,14,.46);
  backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;
  padding:24px;opacity:0;pointer-events:none;transition:opacity .3s;
}
.newspop.open{opacity:1;pointer-events:auto;}
/* While it's open, main.js also adds this to <html> — hides .swipe-chrome
   (ydots/down-arrow/left-right swipe arrows) outright rather than leaving
   them dimly visible through .newspop's translucent/blurred backdrop. */
html.newspop-open .swipe-chrome{display:none;}
.newspop-card{
  background:#fff;border-radius:var(--r);padding:36px 30px 32px;width:100%;max-width:480px;
  max-height:80vh;overflow-y:auto;position:relative;transform:translateY(14px);
  transition:transform .35s var(--ease);
}
.newspop.open .newspop-card{transform:translateY(0);}
.np-close{position:absolute;top:14px;right:16px;background:none;border:none;font-size:26px;line-height:1;color:var(--gray);cursor:pointer;}
.np-close:hover{color:var(--ink);}
.np-tag{display:inline-block;font-size:9.5px;letter-spacing:.14em;color:var(--gray);border:1px solid var(--line);border-radius:30px;padding:3px 10px;text-transform:uppercase;margin-bottom:12px;}
.np-date{font-family:var(--serif);font-size:11px;letter-spacing:.1em;color:var(--gray);margin-bottom:8px;}
.np-title{font-family:var(--serif);font-weight:400;font-size:21px;line-height:1.45;margin-bottom:16px;}
/* white-space:pre-wrap renders the blank-line paragraph breaks that
   front-page.php inserts (at each </p> boundary) when it builds the full
   post body for data-body — plain textContent would otherwise collapse
   them into one run-on block. .newspop-card itself already scrolls
   (max-height:80vh;overflow-y:auto above) so a long announcement's full
   text is never cut off, just scrolled. */
.np-body{font-size:13.5px;line-height:1.95;color:var(--ink-2);white-space:pre-wrap;}
@media(prefers-reduced-motion:reduce){.newspop,.newspop-card{transition:none;}}

@media(min-width:960px){
  .hero{min-height:88vh;padding:100px 0 100px;}
  .hero-h1{font-size:76px;}
  .hero-inner{max-width:720px;}
}

/* =========================================================
   3. Section rhythm
========================================================= */
.section{padding:70px 0;border-top:1px solid var(--line-2);box-sizing:border-box;}
.section.dark{background:var(--ink);color:#fff;}
.section.dark .eyebrow,.section.dark .kicker{color:#9a9a9a;}
.section.dark .lead{color:#bdbdbd;}
.section.dark .title,.section.dark h3.big{color:#fff;}
.section-head{max-width:680px;margin-bottom:36px;}
@media(min-width:960px){.section{padding:110px 0;}}

/* Service page FV only — pairs .section-head with the DNA graphic
   (assets/images/dna.png). Side-by-side on PC/TAB; SP switches to a
   column so the image drops below the text (already second in the
   markup, so no explicit order needed). */
.fv-with-image{display:flex;align-items:center;justify-content:space-between;gap:40px;margin-bottom:36px;}
.fv-with-image .section-head{margin-bottom:0;flex:1;}
.fv-image{flex:0 0 auto;width:30vw;display:none;} /* SP only — see the max-width:700px override below */
.fv-image img{width:100%;height:auto;display:block;}
@media(max-width:700px){
  .fv-with-image{flex-direction:column;align-items:flex-start;gap:24px;}
  .fv-image{width:220px;align-self:center;display:block;}
}

/* Every breakpoint: each section reads as one full screen while scrolling
   (matches the swipe-experience Y-axis snap). min-height only grows the box
   for taller content — nothing is ever clipped.
   100dvh (not 100vh): on phones, 100vh is a fixed value based on the
   viewport with the address bar hidden — while the bar is actually showing
   (e.g. right after a page loads), the real visible area is shorter than
   that, so a wcard-section built on 100vh doesn't reach the bottom of the
   screen on real devices. 100dvh instead tracks whatever the visible
   viewport actually is at any given moment. */
.section{min-height:calc(100dvh - var(--header-h));display:flex;align-items:center;}
.section > .container{width:100%;}
@media(max-width:700px){.section{align-items:flex-start;}}
/* TOP page keeps align-items:center through the tablet range (only
   dropping to flex-start below 700px, per the rule above) — every other
   page instead switches to flex-start for the whole non-PC range
   (client request: content on those pages reads better top-aligned on
   TAB, not vertically centered). body.front-page is added by WordPress
   only on the static front page, so this leaves TOP untouched. */
@media(max-width:959px){
  body:not(.front-page) .section{align-items:flex-start;}
}

/* MVV — each row is an overline label (English term + Japanese gloss, set
   together as one line like the "What we are｜MVV" kicker above it) followed
   by one large serif statement line, separated by a subtle hairline (top
   border on mobile where rows stack, left border on desktop where they sit
   side-by-side as a grid — 2 columns now that the MISSION row was removed
   per client request, leaving just VISION/VALUE). */
.mvv{display:grid;gap:40px;margin-top:0;}
.mvv .row{padding-top:32px;border-top:1px solid var(--line-2);}
.mvv .row:first-child{padding-top:0;border-top:none;}
.mvv .k{display:flex;align-items:baseline;margin-bottom:14px;}
.mvv .k b{font-family:var(--serif);font-size:20px;font-style:italic;font-weight:400;letter-spacing:.1em;}
.mvv .k small{margin-left:10px;font-size:11px;letter-spacing:.16em;color:var(--gray);}
.mvv .v{font-family:var(--serif);font-weight:400;font-size:22px;line-height:1.55;letter-spacing:.02em;}
.mvv .v.sm{font-size:22px;line-height:1.55;}
@media(min-width:960px){
  .mvv{grid-template-columns:repeat(2,1fr);gap:36px;margin-top:16px;}
  .mvv .row{padding-top:0;border-top:none;border-left:1px solid var(--line-2);padding-left:32px;}
  .mvv .row:first-child{border-left:none;padding-left:0;}
  .mvv .k b{font-size:26px;}
  .mvv .v,.mvv .v.sm{font-size:26px;}
}

/* Service page's 01/02 jump links now reuse the Contents hub's
   .hub-grid/.hub-card parts directly (see page-service.php, and
   .hub-grid/.hub-card further down for the actual visual rules) instead
   of their own bespoke row style. .sanchor on the wrapper carries no
   CSS at all anymore — it's kept purely as a bare marker class for
   main.js's click interceptor (see the `a.closest('.sanchor')` check
   there, which is what makes these links do a real full-page reload
   instead of an animated row-jump). */

/* .service-block is a standalone <section class="section service-block">
   (see page-service.php), so spacing/border already come from .section —
   nothing extra needed here beyond the two-column layout below. (Briefly
   merged into one row to fix the .sanchor "looks like a content swap"
   complaint — reverted back to 3 separate panels per client request; the
   actual fix for that now lives in the height/transform transition timing
   below instead — see html.swipe-js-ready .swipe-stage/.swipe-track.) */
.sublist{display:flex;flex-direction:column;gap:15px;margin-top:32px;}
.sublist li{padding-top:15px;border-top:1px solid var(--line-2);}
.sublist li:first-child{padding-top:0;border-top:none;}
.sublist li b{display:block;font-weight:600;font-size:16px;letter-spacing:.03em;margin-bottom:8px;color:var(--ink);}
.sublist li b::before{content:"—  ";color:var(--gray);}
.sublist li span{font-size:14.5px;line-height:1.9;color:var(--ink-2);}
@media(min-width:960px){
  .service-grid{display:grid;grid-template-columns:1fr 1.4fr;gap:60px;align-items:start;}
}

/* stats — the numbers inside <b> count up from 0 on scroll-into-view,
   see the "stat count-up" block in assets/js/main.js. tabular-nums keeps
   each digit the same width while it animates, so the layout doesn't
   jitter as the value changes. */
.stat{display:flex;align-items:flex-start;justify-content:flex-start;text-align:center;gap:28px;margin-bottom:24px;flex-wrap:wrap;}
.stat .s b{font-family:var(--serif);font-size:36px;font-weight:400;font-variant-numeric:tabular-nums;}
.stat .s small{display:block;font-size:10px;color:var(--gray);letter-spacing:.1em;margin-top:3px;}
/* "実績一覧へ" CTA as the trailing item in the same flex row as the number
   blocks (front-page.php's Works-preview .stat only) — row is centered as a
   whole now, so this no longer needs to be pushed to the far end. */
.stat .stat-more{margin:0;}

/* Works cards */
/* .wfilter used to be one flat flex row mixing 実績カテゴリー(jisseki_cat)
   and 業界カテゴリー(jisseki_industry) pills together with no visual
   distinction — per client request it's a vertical stack of labelled
   .wfilter-group rows (one per taxonomy), with "すべて" (.wfilter-all)
   sitting on its own above both since it resets both at once.
   Each group's own pill list (.wfilter-links) is a single, non-wrapping,
   horizontally-scrollable line rather than flex-wrap — per client request
   this filter must never add height to the page no matter how many terms
   exist (flex-wrap would grow to 2+ lines once a taxonomy has more terms
   than fit one row's width, especially on phones). Pill styling itself
   (.wfilter a) is unchanged aside from the flex/white-space additions
   needed to keep every pill on that one scrollable line. */
.wfilter{display:flex;flex-direction:column;gap:12px;margin:26px 0;}
.wfilter-all{align-self:flex-start;flex:0 0 auto;}
.wfilter-group{display:flex;align-items:center;gap:10px 14px;min-width:0;}
.wfilter-label{flex:0 0 auto;font-size:11px;letter-spacing:.1em;color:var(--gray);white-space:nowrap;}
.wfilter-links{
  display:flex;flex-wrap:nowrap;align-items:center;gap:8px;min-width:0;
  overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;padding-bottom:2px;
}
.wfilter-links::-webkit-scrollbar{display:none;}
.wfilter a{flex:0 0 auto;white-space:nowrap;font-size:11.5px;letter-spacing:.08em;color:var(--ink-2);border:1px solid var(--line);border-radius:40px;padding:7px 14px;text-decoration:none;transition:.2s;}
.wfilter a:hover,.wfilter a.is-active{background:var(--ink);color:#fff;border-color:var(--ink);}

/* Client follow-up: 業種(jisseki_industry) filterの子カテゴリー展開UI
   （親をホバー/タップすると子カテゴリーのパネルが下に開く仕様）は
   PC/TABに復元。.wfilter-industry-summaryは分割ピル —
   .wfilter-industry-linkは他のピル同様、親自身のアーカイブへの実リンク、
   .wfilter-industry-caretは別のヒットターゲットとしてナビゲーションせずに
   パネルを開閉する専用ボタン(タッチデバイスは:hoverを持たないため)。
   ネイティブの<details>/<summary>は使わない — <details>の開閉は
   スムーズなフェード/スライドを付けられない(中身はただの[open]までの
   display:none)ため、常に存在する要素をCSSでopacity+transformによって
   フェード/スライドさせる方式。.is-openはmain.jsの
   ginalcaInitIndustryFilter()がキャレットのクリック/タップで切り替える。
   overflow:visible(対応範囲で使われる.wfilter-linksの既定
   overflow-x:auto/overflow-y:hidden単一行スクロールとは違う)により、
   パネルがクリップされずに行の外側の絶対配置オーバーレイとして出せる。
   flex-wrapにより、親のみの(元より短い)ピル行自体は必要なら2行目に
   折り返せる — 対応範囲のフラットな横スクロール方式には依存しない。 */
.wfilter-links--industry{flex-wrap:wrap;overflow:visible;}
/* Client request: SPでは業種の絞り込みも対応範囲と同じ、折り返さない
   横一列スクロールにしたい。ここだけ上のflex-wrap:wrap/overflow:visibleを
   打ち消し、.wfilter-linksの既定(nowrap+横スクロール)に戻す。 */
@media(max-width:700px){
  .wfilter-links--industry{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;}
}
.wfilter-industry{position:relative;flex:0 0 auto;}
.wfilter-industry-summary{display:inline-flex;align-items:center;gap:2px;white-space:nowrap;border:1px solid var(--line);border-radius:40px;padding:0 8px 0 14px;transition:.2s;}
/* .wfilter-industry-link is still a plain <a> matched by the general
   ".wfilter a" rule above (border/border-radius/padding pill styling) —
   ".wfilter-industry-summary" (the wrapping span) is what should look
   like the pill here instead, so a.wfilter-industry-link (type+class,
   same specificity as ".wfilter a", winning on source order) resets
   those back off. */
a.wfilter-industry-link{border:0;border-radius:0;padding:7px 0;flex:0 0 auto;font-size:11.5px;letter-spacing:.08em;color:var(--ink-2);text-decoration:none;}
a.wfilter-industry-link:hover{background:none;color:var(--ink-2);border-color:transparent;}
.wfilter-industry-caret{width:18px;height:18px;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;border:0;background:none;padding:0;margin:0;cursor:pointer;color:inherit;}
.wfilter-industry-caret::after{content:"";width:5px;height:5px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg);margin-top:-3px;transition:transform .2s;}
.wfilter-industry-summary:hover,.wfilter-industry-summary.is-active{background:var(--ink);border-color:var(--ink);}
.wfilter-industry-summary:hover a.wfilter-industry-link,.wfilter-industry-summary.is-active a.wfilter-industry-link{color:#fff;}
/* Client request: the caret icon (currentColor, inherited from
   .wfilter-industry-summary's text color) was staying dark on the dark
   .is-active/:hover background above, making it invisible — switch it to
   white in both states, same as the link text just above. */
.wfilter-industry-summary:hover .wfilter-industry-caret,.wfilter-industry-summary.is-active .wfilter-industry-caret{color:#fff;}
.wfilter-industry:hover .wfilter-industry-caret::after,
.wfilter-industry.is-open .wfilter-industry-caret::after{transform:rotate(-135deg);margin-top:3px;}
.wfilter-industry .wfilter-industry-children{
  position:absolute;top:calc(100% + 8px);left:0;z-index:30;
  display:flex;flex-wrap:wrap;gap:8px;min-width:190px;max-width:280px;
  background:#fff;border:1px solid var(--line);border-radius:14px;padding:10px;
  box-shadow:0 12px 30px rgba(0,0,0,.12);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .22s ease,transform .22s ease,visibility 0s linear .22s;
}
.wfilter-industry:hover .wfilter-industry-children,
.wfilter-industry.is-open .wfilter-industry-children{
  opacity:1;visibility:visible;transform:translateY(0);
  transition:opacity .22s ease,transform .22s ease,visibility 0s linear 0s;
}
/* Client request: SPでの子カテゴリー展開（キャレットタップで開くパネル）は
   引き続き操作しづらいため非表示のまま。SPは「業種」の親カテゴリーの
   ピルだけを表示し、キャレット自体を非表示にして展開の入り口をなくす
   （親ピルのリンクはそのまま自分の実績アーカイブへの通常リンクとして
   機能する）。PC/TABはこの@media外の上のルールがそのまま適用される。 */
@media(max-width:700px){
  .wfilter-industry .wfilter-industry-children{display:none;}
  .wfilter-industry-caret{display:none;}
  /* the caret's own removal above leaves .wfilter-industry-summary's
     asymmetric 14px/8px (left/right) padding — written to make room for the
     caret next to the right edge — looking uneven now that the pill is just
     the link. Even 14px on both sides, matching the plain .wfilter a pills. */
  .wfilter-industry-summary{padding:0 14px;}
}

.wcard{position:relative;border-radius:var(--r);overflow:hidden;color:#fff;min-height:340px;display:flex;text-decoration:none;}
.wbg{position:absolute;inset:0;z-index:0;background:linear-gradient(155deg,#575757,var(--ink));}
.wbg::before{content:attr(data-mark);position:absolute;right:-4%;top:-2%;font-family:var(--serif);font-style:italic;font-size:180px;line-height:.8;color:rgba(255,255,255,.10);}
@media(min-width:960px){
  .wbg::before{font-size:25vw;}
}
.wbg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.28) 45%,rgba(0,0,0,.86) 100%);}
.wbody{position:relative;z-index:2;padding:24px 22px;display:flex;flex-direction:column;justify-content:space-between;width:100%;gap:10px;}
/* Featured-image thumbnail — always rendered (see
   ginalca_render_jisseki_card): the post's own featured image if one is
   set, otherwise a shared assets/images/work_noimg.png placeholder, so the
   slot's size/spacing never shifts between cards. Sits between .wcat and
   .wclient, full-width within .wbody's own padding at a fixed 2:1 ratio,
   distinct from .wbg's full-card decorative gradient behind everything. */
.weyecatch{width:100%;aspect-ratio:2/1;border-radius:12px;overflow:hidden;flex:0 0 auto;margin-bottom:10px;}
.weyecatch img{width:100%;height:100%;object-fit:cover;display:block;}
/* Client request: same auto-playing, cross-fading slideshow as
   single-jisseki.php's DELIVERABLE block (1枚目はアイキャッチ、2枚目以降は
   _jisseki_eyecatch_extra), now with dot indicators too (see the PHP
   comment in ginalca_render_jisseki_card()). .weyecatch already
   establishes the fixed-aspect-ratio box every card needs, so unlike
   .jisseki-eyecatch-stage there's no separate "stage" element — the
   slides position:absolute directly inside .weyecatch itself. */
.weyecatch--slideshow{position:relative;}
.weyecatch-slide{position:absolute;inset:0;opacity:0;transition:opacity 1.2s ease;}
.weyecatch-slide.is-active{opacity:1;z-index:1;}
.weyecatch-slide img{width:100%;height:100%;object-fit:cover;display:block;}
/* Dots sit as an overlay on top of the slides (not extra markup height
   below them) so .weyecatch's fixed size across every card is unaffected
   by whether a given card happens to have 2+ images. */
.weyecatch-dots{position:absolute;left:0;right:0;bottom:8px;z-index:2;display:flex;justify-content:center;gap:6px;}
.weyecatch-dot{width:6px;height:6px;border-radius:50%;border:0;padding:0;background:rgba(255,255,255,.55);cursor:pointer;transition:.2s;}
.weyecatch-dot:hover{background:rgba(255,255,255,.85);}
.weyecatch-dot.is-active{background:#fff;width:16px;border-radius:3px;}
/* TOP's Works teaser (the only .rail on front-page.php) hides the
   thumbnail — client request, it was making the card too tall there.
   Scoped to body.swipe-key-top so the same .wcard partial's weyecatch
   still shows everywhere else it's reused (Works archive, single-jisseki
   "other works" rail). */
body.swipe-key-top .rail .weyecatch{display:none;}
.wtype{align-self:flex-start;display:inline-block;font-family:var(--serif);font-size:9.5px;letter-spacing:.18em;padding:4px 11px;border:1px solid rgba(255,255,255,.45);border-radius:30px;margin-top:6px;}
.wtype.quant,.wtype.qual{background:rgba(255,255,255,.95);color:#111;border-color:transparent;}
.wlogo{font-family:var(--serif);font-size:32px;letter-spacing:.02em;line-height:1;}
/* .wlogo-row places .wlogo and its 業界カテゴリー(industry, .windustry)
   labels side by side; wraps to its own line (with a bit of top margin —
   see .hero-content .windustry below) on narrower cards/viewports where
   they don't fit on one line. */
.wlogo-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
.windustry{display:flex;gap:6px;flex-wrap:wrap;margin:0;}
.windustry span,.windustry a{font-size:9.5px;letter-spacing:.1em;color:rgba(255,255,255,.82);border:1px solid rgba(255,255,255,.32);border-radius:2px;padding:3px 8px;}
/* Client request: .hero-content内のみ<a>化 — テキスト装飾を消し、
   ホバー時に少し目立たせる。 */
.hero-content .windustry a{text-decoration:none;transition:.2s;}
.hero-content .windustry a:hover{color:#fff;border-color:#fff;}
/* single-jisseki.php's hero — .wlogo runs much larger there (44px, set
   inline), so the industry labels wrap below it far more often; give that
   wrapped state some breathing room from the title above it. */
.hero-content .windustry{margin:10px 0 0;}
/* 実績カテゴリー(jisseki_cat) — restored to its original pill style and
   position, right under .wlogo-row, unchanged from before .windustry was
   introduced. Still the taxonomy that powers the Works-archive filter nav
   (.wfilter). */
.wcat{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 10px;}
.wcat span,.wcat a{font-size:9.5px;letter-spacing:.1em;color:rgba(255,255,255,.82);border:1px solid rgba(255,255,255,.32);border-radius:30px;padding:3px 8px;}
.hero-content .wcat a{text-decoration:none;transition:.2s;}
.hero-content .wcat a:hover{color:#fff;border-color:#fff;}
/* single-jisseki.php's hero only — its own spacing above the .wlogo-row. */
.hero-content .wcat{margin:13px 0 0;}
/* Hidden everywhere the card renders (front-page teaser, Works archive,
   single-jisseki "other works") per the client's request — the PHP still
   outputs it (see ginalca_render_jisseki_card), just not shown visually. */
.wclient{display:none;font-size:13px;font-weight:600;letter-spacing:.03em;}
/* The excerpt is now always rendered in full by PHP (see
   ginalca_render_jisseki_card()) — this clamps it back down to a tidy
   2 lines everywhere the card renders, including the Works archive's SP
   full-bleed view (see .wcard-section .wbody further down).
   flex-shrink:0 matters here: .wbody is a flex column (justify-content:
   space-between/center), and on real devices the stacked content
   (eyecatch image + tags + excerpt + stats) can add up to more height than
   the card has room for. Without flex-shrink:0, the flex algorithm was
   free to squeeze this -webkit-line-clamp box down below its own 2-line
   height, which on-device showed up as the excerpt getting cut off after
   just 1 line instead of clamping cleanly at 2. */
.wcmt{
  font-size:12.5px;line-height:1.75;color:rgba(255,255,255,.86);margin-top:0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;
  flex-shrink:0;
}
.wmetrics{display:flex;gap:20px;margin-top:0;flex-wrap:wrap;}
.wmetrics .wm b{font-family:var(--serif);font-size:26px;font-weight:400;line-height:1;}
.wmetrics .wm small{display:block;font-size:9.5px;letter-spacing:.06em;color:rgba(255,255,255,.72);margin-top:5px;}
.wqual{margin-top:0;display:flex;flex-direction:column;gap:8px;}
.wqual li{font-size:12.5px;line-height:1.55;color:rgba(255,255,255,.9);padding-left:16px;position:relative;}
.wqual li::before{content:"—";position:absolute;left:0;color:rgba(255,255,255,.55);}
.wurl{font-family:var(--serif);font-size:16px;letter-spacing:.04em;color:#fff;margin-top:16px;display:inline-flex;gap:5px;text-decoration:none;border-bottom:1px solid #fff;padding-bottom:2px;align-self:flex-start;}
/* Visual cue that the whole .wcard is a link to the case-study detail page
   (the card itself is the <a>, this is just a legible hint, not a nested link). */
.wmore{font-family:var(--serif);font-size:11px;letter-spacing:.08em;color:rgba(255,255,255,.85);margin-top:18px;align-self:flex-start;transition:.25s;}
.wcard:hover .wmore{color:#fff;}

/* Works single detail — accent color is now the same fixed dark tone used
   everywhere else on the site (matches .wbg's fixed gradient), instead of a
   per-project color picked in the metabox. */
.jisseki-detail{max-width:760px;}
.jisseki-detail .hero-block{background:linear-gradient(155deg,#1c1c1c,var(--ink));border-radius:var(--r);overflow:hidden;position:relative;margin-bottom:32px;}
/* Same faint corner-letter watermark as the .wcard preview (.wbg::before),
   reused here so the detail page's hero reads as an extension of its card. */
.hero-block .hero-mark::before{content:attr(data-mark);position:absolute;right:-2%;top:-6%;font-family:var(--serif);font-style:italic;font-size:150px;line-height:.8;color:rgba(255,255,255,.12);}
.hero-block .hero-content{position:relative;z-index:1;}
/* Heading + achievement content share one bordered box, for both the
   quantitative (.stat) and qualitative (.sublist) variants. */
.jisseki-detail .jisseki-results{margin-top:12px;padding:28px 26px;border:1px solid var(--line-2);border-radius:var(--r);background:rgba(255,255,255,.55);backdrop-filter:blur(6px);}
.jisseki-detail .jisseki-results .wtype{margin-bottom:20px;font-size:14px;}
@media(max-width:700px){.jisseki-detail .jisseki-results .wtype{display:table;margin-left:auto;margin-right:auto;}}
.jisseki-detail .wtype.stat-label{background:var(--ink);color:#fff;border-color:transparent;}
.wtype.qual.stat-label,.wtype.quant.stat-label{padding:4px 16px;}
.jisseki-detail .jisseki-results .stat{margin-bottom:0;gap:0;}
.jisseki-detail .stat .s{flex:1 1 140px;padding:0 24px;border-left:1px solid var(--line-2);text-align:center;}
@media(max-width:700px){.jisseki-detail .stat .s{padding:0;border-left:none;line-height:1.4;}}
@media(max-width:700px){.jisseki-detail .stat .s b,.jisseki-detail .stat .s small{white-space:nowrap;}}
@media(max-width:700px){.stat .s small{margin-top:0;margin-bottom:10px;}}
.jisseki-detail .stat .s small{font-size:14px;}
.jisseki-detail .stat .s:first-child{padding-left:0;border-left:none;}
.jisseki-detail .stat .s b{font-size:42px;color:var(--ink);font-variant-numeric:tabular-nums;}
.jisseki-detail .jisseki-results .sublist{margin-top:0;}
.jisseki-detail .sublist li b::before{color:var(--gray);}
/* single-jisseki.php's qualitative-points list has no <b> (just <li><span>),
   so give that plain variant the same dash marker + accent color here. */
.jisseki-detail .sublist li:not(:has(b)) span::before{content:"—  ";color:var(--gray);}
.jisseki-detail .wurl{color:var(--ink);border-color:var(--ink);}
.jisseki-detail .linkbtn{border-color:var(--ink);color:var(--ink);}

/* Prev/next between case studies — also shared by .post-pager (single.php's
   blog-post prev/next) and .oshirase-pager (single-oshirase.php's news-post
   prev/next), same visual treatment for all three content types. */
.jisseki-pager,.post-pager,.oshirase-pager{display:flex;justify-content:space-between;gap:20px;margin-top:56px;padding-top:28px;border-top:1px solid var(--line-2);}
.jisseki-pager a,.post-pager a,.oshirase-pager a{display:flex;align-items:center;gap:14px;max-width:46%;text-decoration:none;color:var(--ink);transition:.2s;}
.jisseki-pager a:hover,.post-pager a:hover,.oshirase-pager a:hover{color:var(--gray);}
.jisseki-pager .jp-next,.post-pager .jp-next,.oshirase-pager .jp-next{margin-left:auto;text-align:right;}
.jisseki-pager .chev,.post-pager .chev,.oshirase-pager .chev{flex:0 0 auto;font-size:20px;}
.jisseki-pager .jp-label,.post-pager .jp-label,.oshirase-pager .jp-label{display:flex;flex-direction:column;gap:4px;min-width:0;}
.jisseki-pager .jp-sub,.post-pager .jp-sub,.oshirase-pager .jp-sub{font-family:var(--serif);font-size:10.5px;letter-spacing:.14em;color:var(--gray);}
.jisseki-pager .jp-title,.post-pager .jp-title,.oshirase-pager .jp-title{font-size:14px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
@media(max-width:700px){.jisseki-pager .jp-title,.post-pager .jp-title,.oshirase-pager .jp-title{max-width:34vw;}}

/* Works detail — optional featured image, shown only when the post has one
   set (see single-jisseki.php), sitting between .jisseki-comment and the
   photo gallery grid. */
.jisseki-eyecatch{margin-top:56px;}
.jisseki-eyecatch img{width:100%;height:auto;border-radius:14px;display:block;}
/* Client request: when 1+ additional DELIVERABLE images are set
   (_jisseki_eyecatch_extra, メタボックスの「DELIVERABLE追加画像」), this
   becomes an auto-playing, cross-fading slideshow instead of a single
   static image (main.js's plain top-level setInterval block, right after
   the gallery-lightbox code — this page never goes through the
   swipe/panel AJAX re-fetch, so no root-taking init function is needed
   here). All slides use the 'ginalca-wide' image size (a hard 1600×900
   crop, i.e. a fixed 16:9), so the stage can be given that same
   aspect-ratio and every slide will exactly overlay the others — no
   layout jump between slides of different natural proportions. */
.jisseki-eyecatch-stage{position:relative;width:100%;aspect-ratio:16/9;border-radius:14px;overflow:hidden;}
.jisseki-eyecatch-stage img{width:100%;height:100%;object-fit:cover;display:block;border-radius:0;}
.jisseki-eyecatch-slide{position:absolute;inset:0;opacity:0;transition:opacity 1.2s ease;}
.jisseki-eyecatch-slide.is-active{opacity:1;z-index:1;}
/* Client request: dot indicators below the slideshow — click jumps
   straight to that slide (main.js), and the active dot tracks whichever
   slide is currently showing, whether that's from autoplay or a click. */
.jisseki-eyecatch-dots{display:flex;justify-content:center;gap:9px;margin-top:16px;}
.jisseki-eyecatch-dot{width:8px;height:8px;border-radius:50%;border:0;padding:0;background:var(--line);cursor:pointer;transition:.2s;}
.jisseki-eyecatch-dot:hover{background:var(--ink-2);}
.jisseki-eyecatch-dot.is-active{background:var(--ink);width:22px;border-radius:5px;}

/* Gallery grid (thumbnails) — click opens .gallerypop below at full size */
.jgallery{display:grid;grid-template-columns:1fr;gap:26px;margin-top:72px;}
@media(min-width:700px){.jgallery{grid-template-columns:1fr 1fr;}}
.jgallery-item{position:relative;display:block;width:100%;border:2px solid transparent;border-radius:10px;overflow:hidden;padding:0;background:var(--paper-3);cursor:pointer;aspect-ratio:4/3;transition:.25s;}
.jgallery-item:hover,.jgallery-item:focus-visible{border-color:var(--ink);}
.jgallery-item img{width:100%;height:100%;object-fit:cover;display:block;transition:.3s;}
.jgallery-item:hover img{transform:scale(1.05);}
.jgallery-caption{margin:10px 2px 0;font-size:13px;line-height:1.7;color:var(--ink-2);}
/* Client request: キャプション先頭の「Before（〇〇）：」「After（〇〇）：」
   をラベル装飾で目立たせたい — ginalca_format_gallery_caption()(PHP)/
   ginalcaFormatGalleryCaption()(JS、拡大表示の.gp-caption用)がこの
   マークアップを組み立てる。 */
.jgallery-label{display:inline-block;font-weight:600;font-size:11px;letter-spacing:.05em;padding:2px 9px;border-radius:20px;margin-right:6px;vertical-align:1px;}
.jgallery-label.is-before{background:#595959;color:#fff;}
.jgallery-label.is-after{background:#d64545;color:#fff;}

/* Gallery lightbox — same fixed-overlay/backdrop-blur pattern as .newspop */
.gallerypop{
  position:fixed;inset:0;z-index:300;background:rgba(14,14,14,.92);
  display:flex;align-items:center;justify-content:center;
  padding:24px;opacity:0;pointer-events:none;transition:opacity .3s;
}
.gallerypop.open{opacity:1;pointer-events:auto;}
.gallerypop-inner{position:relative;max-width:min(90vw,1000px);}
.gallerypop-inner::after{
  content:"";position:absolute;left:6%;right:6%;bottom:-10px;height:3px;border-radius:3px;
  background:linear-gradient(90deg,#333,#111);
}
/* Portrait images aren't shrunk to fit 100vh — the viewport caps the height
   and scrolls instead, so tall images stay full width and readable. */
.gp-viewport{max-height:75vh;overflow-y:auto;border-radius:8px;}
.gallerypop-inner img{max-width:100%;display:block;margin:0 auto;border-radius:8px;}
.gp-close{position:absolute;top:-46px;right:0;background:none;border:none;color:#fff;font-size:28px;line-height:1;cursor:pointer;padding:6px;}
.gp-prev,.gp-next{
  position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;
  border:1px solid rgba(255,255,255,.5);background:rgba(0,0,0,.35);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:18px;cursor:pointer;transition:.2s;
}
.gp-prev:hover,.gp-next:hover{background:rgba(0,0,0,.6);}
.gp-prev{left:-58px;}
.gp-next{right:-58px;}
.gp-meta{position:absolute;left:6%;right:6%;top:100%;margin-top:20px;text-align:center;}
.gp-caption{margin:0 0 6px;color:rgba(255,255,255,.85);font-size:13px;line-height:1.6;}
.gp-caption.is-empty{display:none;}
.gp-count{margin:0;color:rgba(255,255,255,.7);font-size:11px;letter-spacing:.12em;}
@media(max-width:820px){
  .gp-prev{left:6px;}
  .gp-next{right:6px;}
  .gp-close{top:6px;right:6px;background:rgba(0,0,0,.45);border-radius:50%;width:36px;height:36px;}
}
@media(prefers-reduced-motion:reduce){.gallerypop,.jgallery-item,.jgallery-item img{transition:none;}}

/* Contents / Blog list */
.clist{display:flex;flex-direction:column;gap:0;margin-top:6px;}
.clist a{display:flex;gap:16px;align-items:center;padding:20px 2px;border-top:1px solid var(--line);text-decoration:none;color:var(--ink);transition:.2s;font-size:14px;}
.clist a:last-child{border-bottom:1px solid var(--line);}
.clist a:hover{color:var(--gray);}
.clist .date{font-family:var(--serif);font-size:14px;color:var(--gray);width:76px;flex:0 0 76px;letter-spacing:.05em;}
.clist .thumb{width:64px;height:64px;flex:0 0 64px;border-radius:8px;overflow:hidden;background:var(--paper-3);}
.clist .thumb img{width:100%;height:100%;object-fit:cover;}
.clist .body{flex:1;}
.clist .ttl{font-size:14px;line-height:1.5;letter-spacing:.02em;margin-right:.5rem;}
.clist .ctag{font-size:9.5px;color:var(--gray);letter-spacing:.1em;margin-top:6px;display:inline-block;border:1px solid var(--line);border-radius:30px;padding:3px 9px;}
.clist .arw{color:var(--gray);font-family:var(--serif);}

.linkbtn{display:inline-block;margin-top:22px;border:1px solid var(--ink);border-radius:40px;padding:13px 26px;font-family:var(--serif);font-size:12.5px;letter-spacing:.1em;color:var(--ink);text-decoration:none;}
.section.dark .linkbtn{border-color:#fff;color:#fff;}
.linkrow{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px;}
.linkrow a{border:none;padding:6px 0;font-family:var(--serif);font-size:12px;letter-spacing:.08em;color:var(--ink);text-decoration:none;}

/* contents hub — plain numbered list rows (no card boxes), each row divided
   by a hairline; matches the site's other "linkbtn/sanchor" list patterns. */
.hub-grid{display:grid;grid-template-columns:1fr;margin-top:26px;border-top:1px solid var(--line-2);}
.hub-card{display:flex;align-items:center;gap:28px;padding:32px 32px 32px 16px;background:#ffffffbd;border-bottom:1px solid var(--line-2);text-decoration:none;color:var(--ink);transition:.25s;}
.hub-card:hover h3{color:var(--gray);}
.hub-card .no{flex:0 0 auto;font-family:var(--serif);font-size:14px;color:var(--gray);}
.hub-card-text{display:flex;align-items:baseline;gap:16px;flex:1;min-width:0;}
.hub-card h3{font-family:var(--serif);font-weight:400;font-size:30px;margin:0;transition:.25s;}
.hub-card p{font-size:13px;color:var(--gray);line-height:1.6;margin:0;}
.hub-card .jump{margin-left:auto;flex:0 0 auto;font-size:16px;color:var(--gray);transition:.25s;}
.hub-card:hover .jump{color:var(--ink);transform:translateX(3px);}
@media(min-width:700px){.hub-grid{grid-template-columns:1fr 1fr;column-gap:48px;}}
@media(min-width:960px){.hub-card h3{font-size:34px;}}
/* Client request: TAB only (between the SP and PC breakpoints below) gets
   its own .hub-card h3 size, distinct from both. */
@media(min-width:700.02px) and (max-width:959.98px){.hub-card h3{font-size:24px;}}
/* TAB+SP: .no stays beside the title/description group, but within that
   group the description drops directly below the title instead of sitting
   inline. */
@media(max-width:959.98px){
  .hub-card-text{flex-direction:column;align-items:flex-start;gap:0;}
}
/* Client report: the Service page's 01/02 hub-card links broke — their
   title+description text ("Marketing Support"/"マーケティング支援" etc.)
   is much longer than Blog/Note or White Paper's, so squeezing it into
   the default side-by-side inline layout above (meant for short pairs)
   left no room to wrap at word boundaries, and Japanese text with no
   spaces wrapped one character per line. .hub-grid-stack (added only on
   the Service page's wrapper, see page-service.php) forces the
   title-above-description stacked layout at every width instead —
   Contents' own hub-card usage (page-contents.php) is untouched. */
.hub-grid-stack .hub-card-text{flex-direction:column;align-items:flex-start;gap:2px;}
/* Client request: compress .hub-card's height on SP specifically (Contents
   page hub list) — smaller padding/gap and a smaller heading/description
   size than the TAB+PC values above, so more rows fit on screen at once. */
@media(max-width:700px){
  .hub-card{padding:18px 18px 18px 12px;gap:14px;}
  .hub-card .no{font-size:12px;}
  .hub-card h3{font-size:20px;}
  .hub-card p{font-size:12px;line-height:1.5;margin-top:2px;}
}
/* TAB+PC only: extra breathing room between rows now that .hub-card has its
   own translucent background fill, so adjacent cards read as separate.
   (SP is excluded — .hub-grid is already single-column there, so the
   border-bottom hairline alone is enough separation.)
   The top hairline also moves from .hub-grid (one line above the whole
   2-column grid) to each .hub-card (one line above every card) here —
   SP keeps it on .hub-grid instead, since there's only one column there. */
@media(min-width:700.02px){
  .hub-grid{border-top:none;}
  .hub-card{margin-bottom:2.8rem;border-top:1px solid var(--line-2);}
}

/* White Paper cards (page-whitepaper.php) — .wp-card is an <a> (whole card
   clickable, same pattern as .wcard on the Works archive) whenever the
   item has a URL, otherwise a plain <div>; see page-whitepaper.php. */
.wp-grid{display:grid;grid-template-columns:1fr;gap:32px;margin-top:28px;}
@media(min-width:700px){.wp-grid{grid-template-columns:repeat(3,1fr);}}
.wp-card{display:flex;flex-direction:column;color:inherit;text-decoration:none;}
.wp-thumb{aspect-ratio:1.91/1;border-radius:var(--r);overflow:hidden;background:var(--paper-3);}
.wp-thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .4s var(--ease);}
a.wp-card:hover .wp-thumb img{transform:scale(1.04);}
.wp-title{font-family:var(--serif);font-weight:400;font-size:18px;line-height:1.5;margin:16px 0 0;}
.wp-desc{font-size:13px;line-height:1.8;color:var(--ink-2);margin:8px 0 0;}
.wp-card .linkbtn{margin-top:16px;align-self:flex-start;transition:.2s;}
a.wp-card:hover .linkbtn{background:var(--ink);color:#fff;}

/* Company table */
.ctable{width:100%;border-collapse:collapse;margin-top:8px;}
.ctable th,.ctable td{text-align:left;font-weight:400;padding:16px 0;border-bottom:1px solid var(--line);vertical-align:top;line-height:1.8;}
.ctable th{width:34%;color:var(--gray);font-size:13px;letter-spacing:.1em;padding-top:18px;}
.ctable td{color:var(--ink-2);font-size:14px;}
.note{font-size:10px;color:var(--gray-2);margin-top:14px;line-height:1.7;}
@media(min-width:960px){.ctable th{width:22%;}}

/* LINE CTA */
.linebtn{display:inline-flex;align-items:center;gap:9px;margin-top:28px;background:#06C755;color:#fff;text-decoration:none;border-radius:40px;padding:15px 28px;font-family:var(--serif);font-size:13px;letter-spacing:.12em;}
.line-ico{width:20px;height:20px;display:inline-block;flex:0 0 auto;}
/* Client request: LINE公式アカウント準備中の間、「LINEで相談する」ボタンを
   クリックできない「公式LINE 準備中」表示にしたい(page-contact.php参照、
   ginalca_line_url未入力の時だけ<a>の代わりに<span>でこのクラスを使う)。
   色を落として非活性であることを見た目でも伝える。 */
.linebtn.is-disabled{background:#9a9a9a;cursor:default;}

/* LINE banner — page-contact.php's CTA, styled to match the site's
   original dark-section design (background:var(--ink), the same
   kicker/h3.big/lead treatment used in .section.dark, and the standard
   green .linebtn) but as one contained card at the bottom of the page's
   single section, rather than its own full 100vh .section.dark panel
   further down the page (client request). Client follow-up: margin-top
   removed entirely (was 60px), and now a <div> rather than an <a> — it
   holds TWO separately-linked buttons (.line-banner-actions) instead of
   being one big link to LINE itself. */
.line-banner{
  display:flex;align-items:center;justify-content:space-between;gap:32px;
  flex-wrap:wrap;background:var(--ink);color:#fff;
  border-radius:20px;padding:44px 48px;margin:0;
}
.line-banner-text .kicker{color:#9a9a9a;}
.line-banner-text h3.big{color:#fff;margin:4px 0 14px;}
.line-banner-text .lead{color:#bdbdbd;margin:0;max-width:480px;}
/* Both CTA buttons stacked, same width — align-items:stretch expands the
   narrower one (linkbtn) out to match the wider one (linebtn, or vice
   versa) since neither has an explicit width of its own; this container
   itself only ever grows to fit whichever button is naturally widest.
   Client request: gap between the two buttons is 20px (was 12px), and
   both buttons' labels use the site's gothic/sans stack (var(--sans))
   instead of the serif one used elsewhere for this kind of button. */
.line-banner-actions{display:flex;flex-direction:column;align-items:stretch;gap:20px;flex:0 0 auto;}
.line-banner .linebtn{margin-top:0;justify-content:center;font-family:var(--sans);}
.line-banner .linkbtn{margin-top:0;border-color:#fff;color:#fff;text-align:center;font-family:var(--sans);}
@media(max-width:700px){
  .line-banner{flex-direction:column;align-items:flex-start;padding:32px 26px;gap:20px;}
  /* Client request: SP only — the "Ginalca Official LINE" kicker is hidden
     (the h3.big heading plus the .lead line added just below it already
     say enough on the narrower screen). */
  .line-banner-text .kicker{display:none;}
}

/* =========================================================
   4. Footer
========================================================= */
/* Slimmed down considerably (56px 0 30px → 22px 0) — the LINE CTA that
   used to open this footer (.footer-line, a .section.dark-style block)
   moved to page-contact.php, and the descriptive footer-brand paragraph
   is gone entirely, so there's a lot less content to pad around now. */
.site-footer{background:var(--ink);color:#cfcfcf;padding:22px 0;}
/* On the 6 swipe-experience pages, the footer is no longer part of
   .swipe-track's document flow at all (see footer.php) — instead it's a
   real position:fixed bar pinned to the viewport bottom, tucked out of
   sight (translateY(100%)) until main.js confirms you're on a column's
   actual last slide (html.at-last-row, set in updateChrome()), per client
   request: it should only ever appear once there's nothing left below to
   swipe past, not be reachable mid-column. Gated behind
   html.swipe-js-ready specifically (not just .swipe-experience) so a
   no-JS/prefers-reduced-motion visitor — who never gets that class at all
   — instead sees this exact same footer as a plain, always-visible,
   normal-document-flow element at the bottom of the (unenhanced,
   real-scrolling) page, same as it's always been. */
html.swipe-js-ready .site-footer{
  position:fixed;left:0;bottom:0;width:100%;z-index:130;
  transform:translateY(100%);
  transition:transform .5s var(--ease);
}
html.swipe-js-ready.at-last-row .site-footer{
  transform:translateY(0);
}
@media(prefers-reduced-motion:reduce){
  /* Same second, independent guarantee as the .swipe-stage rules further
     down — belt-and-braces in case that check is ever bypassed, so this
     never ends up permanently hidden off-screen. */
  html.swipe-js-ready .site-footer{position:static !important;transform:none !important;}
}
/* Company/Contact used to be forced to this same plain static/normal-flow
   footer as the reduced-motion case above (reasoning: their one row is
   always "the last row" instantly, so the fixed/reveal-on-last-row
   behavior would show it right away rather than only once "nothing's left
   to swipe past"). In practice this backfired: .swipe-col is
   position:absolute (needed for X-axis column-swipe), so it contributes
   nothing to normal document flow — with .site-footer forced to
   position:static, it ended up rendering immediately after .swipe-stage's
   own box with nothing below it to reveal by scrolling, i.e. it never
   showed at all (client report: stuck on one screen, footer missing).
   Client confirmed removing this override (letting Company/Contact use
   the same fixed + at-last-row-reveal footer as every other swipe column)
   fixes it — since their row IS the last row from the instant the page
   loads, the footer now simply appears already docked at the viewport
   bottom right away, which is exactly the desired "always visible" result
   for these two, just via the fixed mechanism instead of a static one. */
/* SP: the real <footer> is hidden entirely (not just de-fixed) — its
   movement felt unstable on phones regardless of fixed vs. static, so its
   content has been moved into .mobile-nav .foot instead (see header.php),
   a panel that's always available via the hamburger and never animates
   on its own. Applies on every SP page, not just swipe-experience ones,
   since the hamburger covers all of them. PC/TAB are untouched — the real
   footer still shows there exactly as before. */
@media(max-width:700px){
  .site-footer{display:none;}
}
/* .footer-col (the "Menu" link list) stays hidden per earlier client
   request — kept in the markup (footer.php) in case it's revived, just
   never shown. .footer-grid is gone. */
.footer-col{display:none;}
.footer-col h4{font-size:10.5px;letter-spacing:.2em;color:#8a8a8a;text-transform:uppercase;margin-bottom:16px;}
.footer-links{display:flex;flex-direction:column;gap:10px;}
@media(min-width:560px){
  .footer-links{display:block;column-count:2;column-gap:32px;}
  .footer-links li{break-inside:avoid;margin-bottom:10px;}
}
.footer-col a{font-size:13px;color:#dcdcdc;text-decoration:none;}
.footer-col a:hover{color:#fff;}
/* Two columns (client-specified): left = company name ｜ SNS, right =
   legal links ｜ copyright. Each column's own items are joined with a "｜"
   separator (.footer-row-item below) rather than literal text, so nothing
   stray is left dangling if a column wraps to two lines on narrow
   screens. The old standalone logo block is gone, but the company name
   now carries a short tagline again (.footer-name-tagline, in a dimmer
   color right after "Ginalca Inc.") per client request. */
.footer-bottom{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px 24px;font-size:10.5px;letter-spacing:.08em;color:#7a7a7a;}
.footer-col-left,.footer-col-right{display:flex;flex-wrap:wrap;align-items:center;}
.footer-row-item{display:flex;align-items:center;}
.footer-row-item + .footer-row-item::before{content:'｜';margin:0 16px;color:#fafafa;flex:0 0 auto;}
.footer-legal{display:flex;gap:16px;flex-wrap:wrap;}
.footer-copyright{font-size:10.5px;letter-spacing:.08em;color:#7a7a7a;}
.footer-bottom .sns{display:flex;gap:16px;}
.footer-bottom a{color:#cfcfcf;text-decoration:none;font-family:var(--serif);}
.footer-bottom a:hover{color:#fff;}
/* Client request: these three links read better in gothic (sans-serif)
   than the serif every other .footer-bottom link uses. Extra-specific
   selector (.footer-bottom .footer-legal a) so it reliably wins over the
   generic .footer-bottom a rule above regardless of source order. */
.footer-bottom .footer-legal a{font-family:var(--sans);font-size:90%;}
/* Stays dim even when .footer-name is hovered (higher specificity than
   the generic .footer-bottom a:hover rule above) — only the company-name
   part brightens on hover, not the tagline after it. margin-left (not a
   plain text space) keeps a clear, consistent gap now that "株式会社ジナルカ"
   no longer ends in a period before it. */
.footer-name-tagline{display:inline-block;margin-left:12px;color:#6e6e6e;}
.footer-bottom a:hover .footer-name-tagline{color:#8a8a8a;}
/* SP: the two-column layout above has no room to sit side by side, so it
   stacks — center everything (both columns, and the rows within each)
   rather than leaving it all flush left, per client request. */
@media(max-width:700px){
  .footer-bottom{flex-direction:column;justify-content:center;gap:18px;}
  .footer-col-left,.footer-col-right{justify-content:center;width:100%;gap:10px;}
  .footer-legal,.footer-bottom .sns{justify-content:center;}
  /* The "｜" separators only make sense as a single-line reading order —
     once a column wraps to multiple lines on SP, one would land stranded
     at the start of a row, so hide them here (gap above replaces their
     spacing job). */
  .footer-row-item + .footer-row-item::before{display:none;}
}

/* =========================================================
   5. Breadcrumb / utility
========================================================= */
/* padding-top/bottom only (not the "padding:22px 0" shorthand) — that shorthand
   would zero out the horizontal padding .container already sets, pulling the
   breadcrumb text flush to the edges and out of alignment with everything else. */
.breadcrumb{font-size:11px;letter-spacing:.05em;color:var(--gray);padding-top:22px;padding-bottom:22px;}
.breadcrumb a{color:var(--gray);text-decoration:none;}
.breadcrumb a:hover{text-decoration:underline;}
/* Client request: breadcrumb shows in full on PC/TAB on every page, but is
   dropped entirely on SP site-wide (not just Company/Contact — this used
   to be scoped to just those two pages, since they're fixed to a
   one-viewport-tall swipe panel with little room to spare on SP, but the
   client asked for the same SP-hide treatment on every page). See
   ginalca_get_breadcrumb_items() in inc/template-tags.php for the earlier
   history (that used to drop just the 2nd item on every breakpoint). */
@media(max-width:700px){
  .breadcrumb{display:none;}
}
.pagination{display:flex;gap:10px;margin-top:40px;flex-wrap:wrap;justify-content:center;}
.pagination a,.pagination span{border:1px solid var(--line);border-radius:30px;padding:8px 16px;font-size:12px;text-decoration:none;color:var(--ink);}
.pagination .current{background:var(--ink);color:#fff;border-color:var(--ink);}

.entry-content{max-width:760px;font-size:15px;line-height:2;}
/* Client request: 本文中のh2見出しをもう少し目立たせたい — ink色の左
   アクセントバー+太字化+やや大きめのサイズで、h3(下線区切り)より視覚的な
   重みが上になるように調整。 */
.entry-content h2{font-family:var(--serif);font-weight:600;font-size:26px;line-height:1.4;margin:44px 0 18px;padding-left:18px;border-left:4px solid var(--ink);}
.entry-content h3{font-family:var(--serif);font-size:19px;margin:30px 0 12px;border-bottom:1px solid currentColor;padding-bottom:8px;}
.entry-content p{margin-bottom:20px;}
.entry-content .profile-name{font-size:16px;letter-spacing:.02em;}
.entry-content .profile-name b{font-weight:600;}
/* Client report①: コンテンツ幅(760px)より小さい画像を挿入してもwidth:100%
   相当に拡大される／client report②: メディア設定の「カスタムサイズ」で
   指定したwidth/heightが反映されない。①の対策として一度width:autoを
   指定したが、それがwidth/height属性(カスタムサイズの指定含む)による
   ブラウザの表示サイズ決定を上書きしてしまい②を引き起こしていた —
   widthは指定せず、HTML側のwidth/height属性（＝メディア設定で選んだ
   サイズ）がそのまま使われるようにする。heightだけautoにしておくことで、
   max-width:100%でクランプされた場合も縦横比はwidth/height属性から
   自動計算される(HTML仕様のaspect-ratio既定値)ため崩れない。 */
.entry-content img{border-radius:12px;margin:24px 0;max-width:100%;height:auto;}
/* Client report: 投稿にキャプション付き画像([caption]ショートコード)を
   設置すると、画像がコンテンツ幅(.entry-content、760px)に収まらず
   はみ出す不具合。原因はWordPress側 — functions.phpでadd_theme_support
   ('html5', array(..., 'caption', ...))を指定しているため、[caption]は
   <figure class="wp-caption ...">(要素に画像幅+約10pxのインラインpx
   固定width)+<figcaption class="wp-caption-text">を出力する。この
   固定pxをこのテーマ側で一切キャップしていなかったため、大きいサイズの
   画像(例:1024px)をキャプション付きで入れるとコンテンツ幅を超えて
   はみ出していた。max-width:100%はインラインwidthより仕様上優先して
   使われる(widthはmax-width/min-widthで必ずクランプされる)ため、
   !important無しでも確実に効く。 */
.entry-content .wp-caption{max-width:100%;margin:24px 0;}
.entry-content .wp-caption img{margin:0;} /* 画像自体の上下マージンは.wp-captionの外側マージンに一本化 — キャプション文が写真のすぐ下に来るように */
.entry-content .wp-caption-text{margin:10px 0 0;font-size:12.5px;line-height:1.6;color:var(--gray);text-align:center;}
/* [caption align="..."]で付く配置クラス — WPコアはクラス名のみ出力し、
   スタイルはテーマ側の責任(このテーマにはこれまで定義がなかった)。 */
.entry-content .aligncenter{display:block;margin-left:auto;margin-right:auto;}
.entry-content .alignleft{float:left;margin:4px 24px 20px 0;}
.entry-content .alignright{float:right;margin:4px 0 20px 24px;}
.entry-content ul,.entry-content ol{margin:0 0 20px 22px;list-style:disc;}
.entry-content ol{list-style:decimal;}
/* Client request: 本文にWord/Excel/Googleドキュメント等から表を貼り付けた
   際、素の<table>のままだと見た目が整わない — エディタ側で個別にクラスを
   付けなくても、.entry-content内の<table>全てに自動的にスタイルが当たる
   ようにする(Company概要ページの.ctableとは別の、本文用の汎用スタイル)。
   横幅が広い表がSPではみ出さないよう、.entry-content-table-wrap的な
   ラッパーがなくても効くようoverflow-xを<table>自身の親("画像の場合と
   同様、貼り付け直後は素のtableタグしかない")ではなくtable自体に
   display:blockを与えてスクロール可能にしている。 */
/* Client report: 右端・下端の罫線だけ濃く見える — border-collapse:collapse
   だと、内部の線は隣り合う2つのセルの1px罫線が1本に「合体」して描画される
   一方、表の一番右・一番下は合体する相手セルが無く単独の1pxのまま残る
   ため、アンチエイリアシングの掛かり方が内部線と変わってしまい、同じ
   1pxのはずが右端・下端だけ実際より濃く/太く見えていた。border-collapse:
   separate + border-spacing:0にしたうえで、罫線を各セルの右端・下端の
   border(+ table自身の上端・左端border)だけで引く形に統一し、どの線も
   「1本のborder宣言だけで描かれる」ようにして解消。 */
.entry-content table{width:100%;border-collapse:separate;border-spacing:0;margin:0 0 24px;font-size:13.5px;display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;border-top:1px solid var(--line);border-left:1px solid var(--line);}
.entry-content table th,.entry-content table td{padding:10px 16px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);text-align:left;vertical-align:top;line-height:1.7;}
.entry-content table th{background:var(--paper-3);color:var(--ink-2);font-weight:600;white-space:nowrap;}
.entry-content table td{color:var(--ink-2);}
.entry-content table tr:nth-child(even) td{background:var(--paper-2);}
.entry-meta{display:flex;gap:14px;align-items:center;font-size:11px;color:var(--gray);letter-spacing:.06em;margin-bottom:20px;flex-wrap:wrap;}
.entry-meta .cat{border:1px solid var(--line);border-radius:30px;padding:3px 10px;}

/* Client request: Blog記事詳細ページのタイトル直下に表示する執筆者
   プロフィール(「このブログを書いた人：」)— 添付デザイン準拠。ライトグレー
   のカードに、太字の見出し+下線区切り、その下に丸型写真+名前+経歴文を
   横並びで配置。single.phpのginalca_render_blog_author_box()呼び出しで
   出力される。 */
.blog-author{max-width:760px;margin:32px 0;padding:28px 30px;background:#fff;border:1px solid #ebebeb;border-radius:var(--r);}
.blog-author-label{font-weight:600;font-size:15px;padding-bottom:16px;border-bottom:1px solid var(--line);margin-bottom:20px;}
.blog-author-body{display:flex;align-items:flex-start;gap:22px;flex-wrap:wrap;}
.blog-author-photo{flex:0 0 auto;width:96px;height:96px;border-radius:50%;overflow:hidden;}
/* Client report: photo wasn't clipping into a clean circle — the browser
   was also matching the earlier .entry-content img{border-radius:12px;
   margin:24px 0;} rule (this box sits inside .entry-content, and that
   selector has the same specificity as this one, so its margin/radius
   otherwise leak through on any property this rule doesn't explicitly
   reset). margin:0 and border-radius:0 here override that. */
.blog-author-photo img{width:100%;height:100%;object-fit:cover;display:block;margin:0;border-radius:0;}
.blog-author-text{flex:1 1 260px;min-width:0;}
/* Client report: margin-bottom:10pxが.entry-content p{margin-bottom:20px;}
   に上書きされる — <p class="blog-author-name">は.entry-content内にあり、
   .blog-author-name単体(クラス1つ)は.entry-content p(クラス1つ+要素1つ)
   より詳細度が低いため負けていた。上のphoto/imgと同じ理由・同じ対処法
   (親の.blog-authorを付けて詳細度を上げる)で解決。 */
.blog-author .blog-author-name{font-weight:600;font-size:15px;margin-bottom:10px;}
.blog-author-bio{font-size:13.5px;line-height:1.9;color:var(--ink-2);}
.blog-author-bio p{margin-bottom:12px;}
.blog-author-bio p:last-child{margin-bottom:0;}
@media(max-width:700px){.blog-author{padding:22px 20px;}}

/* Blog個別記事冒頭の自動目次（.post-toc）— .blog-authorと同じ白カード
   +薄いボーダーのトーンに揃えている。見出しが2つ以上ある時だけ
   ginalca_render_blog_toc()が描画する（single.php参照）。 */
.post-toc{max-width:760px;margin:0 0 32px;padding:24px 28px;background:#fff;border:1px solid #ebebeb;border-radius:var(--r);}
.post-toc-title{font-weight:600;font-size:14px;padding-bottom:14px;border-bottom:1px solid var(--line);margin:0 0 14px;}
.post-toc ol{margin:0;padding-left:20px;}
.post-toc li{font-size:13.5px;line-height:1.9;color:var(--ink-2);}
.post-toc a{color:inherit;text-decoration:none;}
.post-toc a:hover{color:var(--ink);text-decoration:underline;}
@media(max-width:700px){.post-toc{padding:18px 20px;}}

/* Client request: 記事に設定したタグ(post_tag)も表示したい — 内容と
   ページャーの間、小さめのピル型ラベルで一覧表示。 */
.post-tags{display:flex;flex-wrap:wrap;gap:8px;max-width:760px;margin:28px 0 0;}
.post-tag{display:inline-block;font-size:12px;letter-spacing:.04em;color:var(--gray);border:1px solid var(--line);border-radius:30px;padding:5px 12px;text-decoration:none;transition:.2s;}
.post-tag:hover{color:var(--ink);border-color:var(--ink);}

/* .table-scroll — wrap any <table> that might be wider than its column
   (e.g. a table pasted into a blog post's entry-content, or a wide data
   table on a custom page) in <div class="table-scroll"><table>...</table>
   </div> so it scrolls horizontally on narrow screens instead of breaking
   the layout or shrinking illegibly. Scrollbar is hidden (same treatment
   as .rail) since the table itself makes the scrollability obvious. */
.table-scroll{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;}
.table-scroll::-webkit-scrollbar{display:none;}
.table-scroll table{width:100%;min-width:560px;border-collapse:collapse;}
.table-scroll th,.table-scroll td{text-align:left;font-weight:400;padding:14px 16px;border-bottom:1px solid var(--line);vertical-align:top;line-height:1.8;white-space:nowrap;}
.table-scroll th{font-size:14px;font-weight:600;letter-spacing:.06em;}
.table-scroll td{color:var(--ink-2);font-size:14px;}

.no-results{padding:60px 0;text-align:center;color:var(--gray);}

/* =========================================================
   6. Swipe experience layer — panel-transition version
   ---------------------------------------------------------
   Recreates the client-provided reference (index3.html): pressing/
   swiping X moves between the site's main "columns" (Top/Service/Works/
   Contents/Company/Contact) and Y moves between the slides (the existing
   .hero/.section blocks) *within* the current column — both as an instant
   transform slide, not a scroll. .site-footer is NOT one of these slides —
   it's a fixed bar pinned to the viewport bottom instead, shown once the
   active row is the column's last one (see the .site-footer rules further
   down and html.at-last-row, toggled in main.js's updateChrome()).
   Every column still has its own real URL (assets/js/main.js fetches a
   column's real page the first time you visit it and reuses the result
   after that — see fetchColumn()), so this is purely a JS enhancement.

   IMPORTANT — fallback safety: the rules just below (un-scoped) are the
   DEFAULT for .swipe-stage/.swipe-col/.swipe-track and deliberately do
   nothing clever — plain document flow, no fixed height, no clipping.
   That's what a visitor with JS disabled (or a search engine) sees: just
   the page's real content stacked normally, exactly as if these wrapper
   elements weren't there. The transform/clipping behaviour only turns on
   once assets/js/main.js adds html.swipe-js-ready — which it only ever
   does when JS actually runs AND prefers-reduced-motion is off — so
   there's no risk of a slow/broken script leaving the page clipped to a
   sliver of its real height.
========================================================= */
.swipe-stage{position:relative;}
.swipe-board{position:relative;}
.swipe-col{position:relative;width:100%;}
.swipe-track{position:relative;}

html.swipe-js-ready .swipe-stage{
  overflow:hidden;
  /* JS sets the real pixel height on load and every col/row change (see
     setStageHeight() in main.js) so each slide is always shown at its own
     natural height — never cropped, never leaving extra blank space.
     Client report: clicking an in-page anchor to jump rows (e.g. the
     Service page's .sanchor) looked like an abrupt content "swap" rather
     than a smooth reveal. Root cause — this box's own height used to
     transition over .45s while the content sliding inside it
     (.swipe-col/.swipe-track below) took .62s: the box finished resizing
     to the DESTINATION row's height well before the slide itself
     finished, so overflow:hidden clipped the tail end of the slide
     against a box already sized for the new content instead of the old —
     reads as a hard cut partway through. Matching this to the exact same
     .62s duration (and easing) as the transform keeps the box and its
     content resizing/sliding in lockstep the whole way, so it reads as
     one continuous reveal instead of two separate, out-of-sync motions. */
  transition:height .62s var(--ease);
  /* Second, CSS-only layer against the same "real scroll fights the
     transform transition" bounce main.js's wheel handler now calls
     preventDefault() to stop — belt-and-suspenders in case the page ever
     ends up with a sliver of real scrollable height (rounding, etc.) that
     something other than that wheel handler tries to scroll/rubber-band. */
  overscroll-behavior:none;
}
html.swipe-js-ready .swipe-board{height:100%;}
html.swipe-js-ready .swipe-col{
  position:absolute;top:0;left:0;height:100%;
  transition:transform .62s var(--ease);
  will-change:transform;
}
html.swipe-js-ready .swipe-col.is-active{z-index:1;}
html.swipe-js-ready .swipe-track{
  /* Matches .swipe-col's .62s exactly (was .52s) — client felt the row
     (Y-axis) transition was less smooth than the column (X-axis) one, and
     a mismatched duration on the same easing curve was the culprit. */
  transition:transform .62s var(--ease);
  will-change:transform;
}
/* Slides keep their existing .hero/.section styling untouched — this just
   stops each one's own top/bottom border & snap-related declarations from
   doing anything now that there's no real scrolling left on these pages. */
html.swipe-js-ready .swipe-track > *{scroll-snap-align:none;}

@media(prefers-reduced-motion:reduce){
  /* Never enhanced under reduced motion — see main.js, which simply never
     adds html.swipe-js-ready in that case — but this rule is a second,
     independent guarantee: even if that check were ever bypassed, nothing
     here can end up clipping the page shorter than its content. */
  html.swipe-js-ready .swipe-stage{overflow:visible !important;height:auto !important;}
  html.swipe-js-ready .swipe-col{position:relative !important;transform:none !important;}
  html.swipe-js-ready .swipe-track{transform:none !important;}
}

/* First-visit loading/gesture guide — shown once (a COOKIE set by
   assets/js/main.js on dismiss stops header.php from rendering it again)
   explaining the X/Y swipe navigation above. Sits on the ordinary page
   content rather than a blank screen — a near-opaque white layer lets the
   actual hero/background show through faintly underneath, so it reads as
   "here's the page, here's how to move around it" rather than a separate
   splash screen. Dismissed by clicking anywhere on it (background, the
   arrows, or the button — all just bubble up to the same handler), by
   Escape, or automatically after AUTO_DISMISS_MS (see main.js) — no
   drag-to-dismiss this time, that's what caused the real-device scroll/
   timing issues fixed above. */
.intro-overlay{
  position:fixed;inset:0;z-index:400;
  background:rgba(255,255,255,1);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:64px;
  cursor:pointer;opacity:1;transition:opacity .5s var(--ease);
}
.intro-overlay.is-hidden{opacity:0;}
.intro-welcome p{
  font-family:var(--serif);font-size:14px;line-height:1.9;letter-spacing:.06em;
  color:var(--ink-2);text-align:center;
}
.intro-welcome p + p{margin-top:20px;}
.intro-tap{
  display:block;margin:28px auto 0;font-family:var(--serif);font-size:12px;letter-spacing:.16em;
  color:#fff;background:var(--ink);border:none;border-radius:40px;padding:12px 34px;
  cursor:pointer;transition:.2s;
}
.intro-tap:hover{background:var(--ink-2);}
/* ↓ (vertical-swipe cue) now sits directly under the TOPへ button, inside
   .intro-welcome's own flow — client request (it used to live in
   .intro-compass below, absolutely centered independent of the button). */
.intro-welcome .intro-arrow-down{display:block;margin:24px auto 0;text-align:center;}
/* ← → still read as a diagram of the horizontal-swipe gesture, spanning
   almost the full width so they sit near the actual left/right screen
   edges. Positioned to the screen's vertical center (independent of the
   welcome text's own height above it) via position:absolute against
   .intro-overlay, rather than living in that flex column alongside it. */
.intro-compass{
  position:absolute;top:50%;left:0;right:0;transform:translateY(-50%);
  width:100%;max-width:640px;margin:0 auto;padding:0 40px;
}
.intro-row{width:100%;display:flex;justify-content:space-between;}
.intro-arrow{font-size:26px;color:var(--ink);line-height:1;display:inline-block;}
/* Each arrow nudges a little in the direction it's pointing — ← left,
   → right, ↓ down — so the diagram reads as motion, not a static glyph. */
.intro-row .intro-arrow:first-child{animation:ginalca-intro-nudge-left 1.6s ease-in-out infinite;}
.intro-row .intro-arrow:last-child{animation:ginalca-intro-nudge-right 1.6s ease-in-out infinite;}
.intro-arrow-down{animation:ginalca-intro-nudge-down 1.6s ease-in-out infinite;}
@keyframes ginalca-intro-nudge-left{0%,100%{transform:translateX(0);}50%{transform:translateX(-8px);}}
@keyframes ginalca-intro-nudge-right{0%,100%{transform:translateX(0);}50%{transform:translateX(8px);}}
@keyframes ginalca-intro-nudge-down{0%,100%{transform:translateY(0);}50%{transform:translateY(8px);}}
@media(prefers-reduced-motion:reduce){
  .intro-overlay{transition:none;}
  .intro-arrow{animation:none;}
}
@media(max-width:700px){
  .intro-overlay{gap:44px;}
  .intro-welcome p{font-size:12.5px;}
  .intro-compass{padding:0 24px;gap:14px;}
  .intro-arrow{font-size:22px;}
}

/* side depth dots (Y position within the current page) — shown on all breakpoints */
.ydots{position:fixed;right:16px;top:50%;transform:translateY(-50%);z-index:120;display:flex;flex-direction:column;gap:10px;align-items:center;pointer-events:none;}
.ydots i{width:5px;height:5px;border-radius:50%;background:var(--gray-2);transition:.3s;display:block;}
.ydots i.on{background:var(--ink);transform:scale(1.7);}

/* down arrow (Y axis — jump to the next slide within this column) — a real
   <button> now (see ginalca_render_swipe_controls()), since it actually
   drives the panel-transition move(0,1) in main.js instead of just being a
   decorative scroll hint. Only ever shown on a column's first slide (the
   FV/hero) — main.js toggles .is-hidden, not the "hidden" attribute, so it
   fades out over opacity's transition below instead of vanishing instantly
   the moment you swipe away from the hero. */
.arrow.down{
  position:fixed;left:50%;bottom:24px;transform:translateX(-50%);z-index:110;
  display:flex;flex-direction:column;align-items:center;gap:10px;
  font-family:var(--serif);font-size:11px;letter-spacing:.2em;color:var(--ink);
  background:none;border:none;padding:0;cursor:pointer;opacity:1;
  transition:opacity .4s;
}
.arrow.down.is-hidden{opacity:0;pointer-events:none;}
/* Client follow-up: Works一覧の各.wcard-section(実績カード)に入っている
   間は、ボタンは表示したまま「Scroll」の文字だけ隠したい(main.jsが
   hide-labelクラスを付け替える)。矢印アイコンだけ残す。 */
.arrow.down.hide-label .lab{display:none;}
.arrow.down .chev{
  width:40px;height:40px;border-radius:50%;border:1px solid var(--ink);
  display:flex;align-items:center;justify-content:center;font-size:15px;
  background:rgba(255,255,255,.85);backdrop-filter:blur(6px);
  animation:ginalca-bob 2s infinite;
}
.arrow.down:hover .chev{background:#fff;}
@keyframes ginalca-bob{0%,100%{transform:translateY(0);}50%{transform:translateY(5px);}}
@media (prefers-reduced-motion: reduce){.arrow.down .chev{animation:none;}}
/* SP: match .swipe-arrow's smaller footprint so the two hints feel consistent */
@media(max-width:700px){
  .arrow.down{gap:5px;font-size:9px;}
  .arrow.down .chev{width:30px;height:30px;font-size:13px;}
  /* Client request: Works一覧(/works/)ページのみ、SPで.arrow.down
     (Scrollボタン)が画面中央下で本文と重なり邪魔になるため、右側
     (.ydotsと同じ列)に寄せたい。body.swipe-key-worksはmain.jsの
     updateChrome()がカラム切替の度に付け替える(index.php参照)。
     Client follow-up: 右側に寄せた後、さらに画面右下の角に近い位置に
     調整したい。right値を.ydots(right:16px)と揃え、bottomも画面端に
     近い値に詰めた。 */
  body.swipe-key-works .arrow.down{left:auto;right:16px;bottom:20px;transform:none;}
}

/* left/right column-swipe arrows (X axis — real page navigation) — circled arrow, label below, bottom edges */
.swipe-arrow{
  position:fixed;bottom:104px;z-index:120;
  display:flex;flex-direction:column;align-items:center;gap:9px;
  text-decoration:none;color:var(--ink);
  font-family:var(--serif);font-size:11px;letter-spacing:.16em;
}
.swipe-arrow .chev{
  width:40px;height:40px;border-radius:50%;border:1px solid var(--ink);
  display:flex;align-items:center;justify-content:center;font-size:16px;
  background:rgba(255,255,255,.85);backdrop-filter:blur(6px);transition:.25s;
}
.swipe-arrow:hover .chev{background:#fff;transform:scale(1.06);}
.swipe-arrow.left{left:18px;}
.swipe-arrow.right{right:18px;}
/* main.js sets the "hidden" attribute (not a class) when there's no prev/
   next column — [hidden] and .swipe-arrow{display:flex} above are equal
   specificity (0,1,0 each), so without this, the later, author-level
   .swipe-arrow rule was winning the cascade and the arrow stayed visible
   despite being "hidden". This attribute-plus-class selector (0,2,0) beats
   both, restoring the actual hide. */
.swipe-arrow[hidden]{display:none;}
/* SP only (≤700px): replaced by .navsub-arrow inside .primary-nav-sub-row
   (see the header section above) — TAB (701–959px) still uses this
   floating labeled pair, same as PC. Placed here (after the base
   .swipe-arrow rule, same specificity) so it actually wins the cascade;
   a max-width override placed earlier in the file would lose to this
   unconditional rule further down. */
@media(max-width:700px){.swipe-arrow{display:none;}}
@media(max-width:700px){
  /* Match .hint.down's stacking (label above, circle below) and bottom
     offset so the left/right arrow circles and the scroll-hint circle
     all line up at the same height on phones. */
  .swipe-arrow{gap:5px;font-size:9px;flex-direction:column-reverse;bottom:24px;}
  .swipe-arrow .chev{width:30px;height:30px;font-size:13px;}
  .swipe-arrow.left{left:6px;}
  .swipe-arrow.right{right:6px;}
}
@media(max-width:480px){
  .swipe-arrow.left{left:4px;}
  .swipe-arrow.right{right:4px;}
}

/* horizontal swipe rail — used for Works cards, matches index2.html's swipe feel at any breakpoint */
.rail{
  display:flex;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;
  margin:0 calc(var(--pad) * -1);padding:6px var(--pad) 18px;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;cursor:grab;
}
.rail::-webkit-scrollbar{display:none;}
.rail.is-dragging{cursor:grabbing;scroll-snap-type:none;user-select:none;}
.rail .wcard{flex:0 0 82%;scroll-snap-align:center;min-height:360px;}
@media(min-width:640px){.rail .wcard{flex:0 0 46%;}}
@media(min-width:1000px){.rail .wcard{flex:0 0 31%;}}

/* Client request: Worksカテゴリーページ（jisseki_cat/jisseki_industry
   タクソノミーアーカイブ）内の.rail .wcardのみ、SPで専用レイアウトに。
   WP標準のtax-*ボディクラスでスコープし、front-page teaserやsingle-jisseki
   の「その他の実績」railは対象外のまま。 */
@media(max-width:700px){
  body.tax-jisseki_cat .rail .wcard,
  body.tax-jisseki_industry .rail .wcard{
    flex:0 0 75%;min-height:unset;
  }
  /* Client follow-up: reverted — .wmore/.wcmt hidden, .wcat's
     margin-bottom:0, and .wbody's justify-content:flex-start (all
     previously applied here) are back to their normal (unmodified)
     display/spacing/alignment on SP. */
}

/* Client request: on PC, cancel the 25vw .wbg::before override (see the
   base rule + its @media(min-width:960px) override further up) for the
   Works category/industry taxonomy archives AND the Works detail page's
   own "その他の実績" rail — both render their cards via the same .rail
   .wcard markup as ginalca_render_jisseki_card()'s 'compact' path. Scoped
   via body.swipe-key-works (set on the main /works/ archive, every
   jisseki_cat/jisseki_industry taxonomy archive, AND single-jisseki.php —
   see header.php) combined with .rail .wcard, which only the taxonomy
   archives and the detail page's rail actually have (the main archive uses
   full-bleed .wcard-section .wcard instead), so the front-page Works
   teaser — which also uses plain .rail .wcard but sits on body.swipe-key-top
   — is correctly left untouched at 25vw. Higher specificity than the bare
   .wbg::before rule above wins the cascade within the same breakpoint. */
@media(min-width:960px){
  body.swipe-key-works .rail .wcard .wbg::before{font-size:180px;}
}

/* Client follow-up: the taxonomy archive pages that .term-pager appears on
   dropped back out of the swipe/panel system (see the comment above
   ginalca_current_swipe_key() in inc/template-tags.php), so there's no
   longer a competing #swipeArrowLeft/Right pair floating in the same
   corners on these pages — .term-pager's prev/next links are plain
   .swipe-arrow elements again (styled with the rest of that class further
   down), same as before that experiment. No dedicated .term-pager rule
   needed here anymore. */

/* Works archive (template-parts/works-loop.php) — one full-bleed card per
   panel/slide at EVERY breakpoint now (client request: unify with what
   used to be the SP-only layout; previously PC/TAB showed these inside a
   horizontal .rail grid via .wcard-section{display:contents}, and only SP
   got the vertical, full-bleed, one-card-per-panel treatment below).
   works-loop.php no longer wraps these in a .rail/.rail-stack-sp div at
   all — each .wcard-section is now a direct swipe-track slide of its own,
   so "1 work = 1 panel" holds everywhere. The front-page teaser rail and
   single-jisseki's "other works" rail still use plain .rail (horizontal
   swipe, every breakpoint) — nothing about those changed. */
.wcard-section{
  display:flex;padding:0;border-top:none; /* full-bleed, no divider */
  position:relative;
  /* No longer overridden to 0 — inherits .section's own
     min-height:calc(100dvh - var(--header-h)), same as every other
     content section, per client request (a work's panel now fills the
     screen just like a .hero/.section slide does, rather than shrinking
     to whatever height its own content happens to need). */
}
/* Stretch .wcard to fill the whole section box edge-to-edge (rather than
   sitting inset within the section's own padding, as it normally does) —
   .wbg already covers 100% of .wcard via its own position:absolute;inset:0,
   so this alone makes the dark background read as full-screen for this
   card's "page". align-self:stretch (overriding .section's own
   align-items:center, which would otherwise just vertically CENTER a
   shorter card and leave the page's own background showing above/below
   it) makes the card grow to fill that full section height too — and, if
   its own content (eyecatch image + tags + excerpt + stats) ever needs
   more than one screen's worth, it simply grows past that and the section
   grows along with it instead of clipping. */
.wcard-section .wcard{
  width:100%;border-radius:0;align-self:stretch;
}
/* .wbody keeps its normal left/right padding (breathing room from the
   now-full-bleed .wcard-section edges), content block vertically
   centered instead of spread top/bottom. */
.wcard-section .wbody{justify-content:center;padding:44px 22px;}
@media(max-width:700px){
  /* Nothing extra needed here anymore — the rules above already apply at
     every width. This query is kept only as a landing spot in case a
     phone-specific tweak is ever needed again. */
}
/* PC/TAB only — Works archive's watermark letter sits flush against the
   card's right edge here (client request), rather than the -4% used by
   every other .wcard (front-page teaser, single-jisseki "other works"),
   where it's meant to bleed slightly past the edge. */
@media(min-width:700px){
  .wcard-section .wbg::before{right:0;}
}
/* PC only — narrows the whole text+photo column to about half the card's
   width, centered, instead of stretching edge-to-edge. .weyecatch is
   width:100% of .wbody at aspect-ratio 2/1, so at full card width on a wide
   PC screen it was coming out very tall; capping .wbody itself keeps the
   photo (and everything else) proportionally smaller instead. SP/TAB
   (below 960px) keep the original full-width column via the .wbody rule
   above, unchanged. */
@media(min-width:960px){
  .wcard-section .wbody{
    max-width:50%;
    margin-left:auto;
    margin-right:auto;
  }
}

/* =========================================================
   7. Site-wide background pattern (per-panel position, no scroll pan)
   A large, low-opacity brand graphic sits fixed behind the whole site.
   Went through a couple of continuous scroll-linked pan effects here
   (sideways via --bg-x, then straight down via --bg-y) — both felt
   unstable/jittery and were removed. Current approach: same per-page
   image, but assets/js/main.js's updateChrome() (fires once per swipe
   panel/row change, NOT continuously during scroll) snaps --bg-y to a
   different fixed background-position for each row within a multi-row
   swipe column (Service/Works/Contents/Top) — client asked specifically
   for this discrete "shift position per panel" version rather than new
   artwork per panel. Single-row columns (Company/Contact) always reset to
   0%. The transition below animates each snap smoothly instead of an
   instant jump.
   Only visible through sections that don't declare their own opaque
   background (.section.dark / .site-header / .site-footer stay solid,
   by design).
   Per-page image, per earlier client request: TOP through Contact (the 6
   swipe columns) each get their own bg_*.png via the body.swipe-key-*
   classes already set in header.php, overriding the bg_top.png fallback
   below (kept as the default for any page outside the swipe sequence,
   e.g. a single 実績 case study or a plain WP page with no template —
   client asked for this fallback to reuse bg_top.png specifically rather
   than a separate shared pattern asset). Single jisseki case studies
   reuse bg_works.png since header.php already gives them swipe-key-works
   for this exact purpose.
========================================================= */
.site-bg{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:url('../images/bg_top.png');
  background-repeat:no-repeat;
  background-size:100% auto;
  background-position:center var(--bg-y);
  transition:background-position .6s var(--ease);
  opacity:.05;
}
body.swipe-key-top .site-bg{background-image:url('../images/bg_top.png');}
body.swipe-key-service .site-bg{background-image:url('../images/bg_service.png');}
body.swipe-key-works .site-bg{background-image:url('../images/bg_works.png');}
body.swipe-key-contents .site-bg{background-image:url('../images/bg_contents.png');}
body.swipe-key-company .site-bg{background-image:url('../images/bg_company.png');}
body.swipe-key-contact .site-bg{background-image:url('../images/bg_contact.png');}
