/*
Theme Name: Unfold Studio 2026
Theme URI: https://unfoldstudio.sg
Author: Unfold Studio
Description: Block theme for unfold — a yoga studio in Singapore. Move. Explore. Become. Ships instructor and class custom post types, and patterns for every section of the studio site.
Version: 1.0.1
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: unfold-studio-2026
Tags: block-theme, full-site-editing, one-column, custom-colors, custom-logo, editor-style
*/

/* =========================================================
   Tokens — bridged to the theme.json palette so both the
   hand-written CSS below and the block editor stay in sync.
   ========================================================= */
:root{
  --ink:      var(--wp--preset--color--ink, #141414);      /* black — 45% */
  --paper:    var(--wp--preset--color--paper, #FFFFFF);    /* white — 35% */
  --bone:     var(--wp--preset--color--bone, #DCCBAC);     /* warm bone — 10% */
  --bone-dim: var(--wp--preset--color--bone-dim, #B8A688);
  --line:     rgba(20,20,20,0.12);
  --line-lt:  rgba(255,255,255,0.18);
  --dur:      var(--wp--custom--duration, 650ms);
  --ease:     var(--wp--custom--ease, cubic-bezier(.16,.84,.44,1));
  --header-h: 5.2rem;
}

/* =========================================================
   Base
   ========================================================= */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

body{
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}

img{ display:block; max-width:100%; height:auto; }
::selection{ background:var(--bone); color:var(--ink); }
b, strong, .bold{ font-weight:700; }

/* Block resets */
figure.wp-block-image,
figure.wp-block-post-featured-image{ margin:0; }
.wp-block-group{ box-sizing:border-box; }
.wp-block-post-template{ list-style:none; margin:0; padding:0; }
.wp-block-post-template > li{ list-style:none; }

section, .section{ position:relative; }

/* =========================================================
   Shared utilities
   ========================================================= */
/* No width:100% — .wrap is content-box, so that plus the padding runs 12vw
   past the band on a phone. A block's auto width already fills it. */
.wrap{ max-width:1200px; margin:0 auto; padding:0 6vw; }

.eyebrow{
  font-size:0.7rem;
  letter-spacing:0.22em;
  font-weight:600;
  color:var(--bone-dim);
  margin:0;
}

.logo{ display:inline-flex; align-items:center; gap:0.5rem; font-size:1.3rem; line-height:1; }
/* The holding page still draws the wordmark in markup (inc/holding-template.php);
   the header and footer use the Site Logo block, whose image is uploaded in the
   editor and sized by the block's own width setting. */
.logo .mark{ width:1.5em; height:1.5em; display:block; }
.logo .word b{ font-weight:700; }
.wp-block-site-logo{ line-height:0; }
.wp-block-site-logo a{ display:block; }
.wp-block-site-logo img{ display:block; height:auto; max-width:100%; }

/* Scroll reveal — paired with initReveal() in assets/js/main.js. */
.reveal{ opacity:0; transform:translateY(30px); transition:opacity .9s var(--ease), transform .9s var(--ease); }
.reveal.is-in{ opacity:1; transform:translateY(0); }
.reveal-delay-1{ transition-delay:.1s; }
.reveal-delay-2{ transition-delay:.2s; }
.reveal-delay-3{ transition-delay:.3s; }

/* =========================================================
   Section scaffolding
   Shared by every section pattern, so it lives here rather than in
   any one patterns/<name>.css.
   ========================================================= */

/* Sections butt straight up against each other — the flow layout's
   default sibling margin would open a white gap between the dark bands. */
main.wp-block-group > .alignfull:not([class*="has-margin-"]){ margin-block:0; }

/* No band in this theme wants the editor's default 24px between blocks:
   every one carries its own padding. Core sets it in two places —

     :where(.wp-site-blocks) > *        the template's top level,
                                        so header / main / footer
     :root :where(.is-layout-flow) > *  inside post-content,
                                        so between the sections

   and both are closed here. The first sits inside :where() and is
   outranked by anything; the second needs two classes to clear core's
   :root prefix. The alignfull rule above predates both and covered this
   back when patterns sat directly in main.

   The :not() is what lets the margin control work. Weakening these rules
   instead would have handed the 24px straight back to core, whose rule is
   the very thing they exist to beat — so rather than lose the fight on
   specificity they step out of it, and a band carrying has-margin-* states
   its own margins. Every unfold band carries both, none included, so
   nothing here is left undeclared. */
.wp-site-blocks > *:not([class*="has-margin-"]){ margin-block:0; }
.section-shell .entry-content > *:not([class*="has-margin-"]){ margin-block:0; }

/* Section spacing. Every unfold/* block carries one class a side, written
   at render time by unfold_render_section_supports() from the shared
   controls in src/index.js — the same arrangement as the tones below.

   Four steps rather than two, and each end set on its own, because the
   awkward measurement was never the height of a band: it was the seam
   where two of them meet and both pay for it. One band's bottom going to
   none is now a single decision, not a .flush-bottom cancelling a .pad-lg
   that was already there. Those two utilities are what this replaces.

   Two scales on the same four steps. Padding is room inside the band, so
   the tone travels through it; margin is room outside, where the page
   shows between two bands. */
.has-pad-top-none{     padding-top:0; }
.has-pad-top-reduced{  padding-top:3.5rem; }
.has-pad-top-normal{   padding-top:6rem; }
.has-pad-top-generous{ padding-top:8rem; }

.has-pad-bottom-none{     padding-bottom:0; }
.has-pad-bottom-reduced{  padding-bottom:3.5rem; }
.has-pad-bottom-normal{   padding-bottom:6rem; }
.has-pad-bottom-generous{ padding-bottom:8rem; }

/* Margins between siblings collapse, so two bands facing each other keep
   the larger of the two rather than the sum. That is the behaviour the
   control describes in the editor — it is not worth a flow-root on the
   page wrapper to defeat it. */
/* The :root prefix is load-bearing, not decoration. Core sets the flow
   margin from :root :where(.is-layout-flow) > *, which is one class deep;
   a bare .has-margin-top-normal would tie it and come down to whichever
   stylesheet the page happened to print last. Two classes settles it. */
:root .has-margin-top-none{     margin-top:0; }
:root .has-margin-top-reduced{  margin-top:3.5rem; }
:root .has-margin-top-normal{   margin-top:6rem; }
:root .has-margin-top-generous{ margin-top:8rem; }

:root .has-margin-bottom-none{     margin-bottom:0; }
:root .has-margin-bottom-reduced{  margin-bottom:3.5rem; }
:root .has-margin-bottom-normal{   margin-bottom:6rem; }
:root .has-margin-bottom-generous{ margin-bottom:8rem; }

/* Section height. Opt-in, unlike the two scales above: a band is as tall as
   whatever it holds unless it says otherwise, so only a block declaring
   "unfoldSection": { "height": true } carries one of these.

   Four named steps and an escape hatch, because the request is never really
   "make it 380 pixels" — it is "that one is too big for this page".

   The three middle steps are multiples of the height the block was drawn at,
   not lengths. That is the whole trick. A step in vh looks right on a laptop
   and turns into a portrait slit on a phone, where there is no width left to
   pay for the extra height: the band would have to crop into the photograph
   to grow. A multiple has no such problem — it shrinks with whatever the
   block's own height was already based on, so one choice holds from a phone
   to a monitor and the crop survives the trip.

   full and custom are lengths, since neither means anything as a proportion.
   Each mechanism clears the other so that nesting stays honest: a band set to
   full inside one set to small must be full, not 0.62 of it. */
.has-height-small{  --unfold-height:initial; --unfold-height-scale:0.62; }
.has-height-normal{ --unfold-height:initial; --unfold-height-scale:1; }
.has-height-large{  --unfold-height:initial; --unfold-height-scale:1.6; }

.has-height-full{   --unfold-height-scale:initial; --unfold-height:100vh; }

/* svh is the screen less the phone's browser chrome — the difference between
   "full page" and "full page and a nudge of scroll". Behind @supports rather
   than the usual two-declaration fallback: a custom property accepts any
   token, understood or not, so the older value has to be kept out of reach
   instead of overridden. */
@supports (height:100svh){
  .has-height-full{ --unfold-height:100svh; }
}

/* Custom. Desktop is the one that has to be filled in; the narrower two fall
   back up the chain when left blank, so one number is a complete answer and
   three are only needed when the widths genuinely disagree. The variables
   themselves are written onto the block at render time by
   unfold_render_section_supports(). */
.has-height-custom{ --unfold-height-scale:initial; --unfold-height:var(--unfold-height-desktop); }

@media (max-width:900px){
  .has-height-custom{
    --unfold-height:var(--unfold-height-tablet, var(--unfold-height-desktop));
  }
}

@media (max-width:600px){
  .has-height-custom{
    --unfold-height:var(--unfold-height-mobile, var(--unfold-height-tablet, var(--unfold-height-desktop)));
  }
}

/* Wedge hand-off between a dark band and the light one after it. Absolutely
   placed so it clears the section's own padding; it carries its own dark
   backdrop, so the transparent half reads as the band above continuing down.
   Unused for now — position it per section, e.g. .studio > .fold{ bottom:0 }. */
.fold{
  position:absolute; left:0; right:0; height:56px; z-index:1;
  background:var(--ink); color:var(--paper); pointer-events:none;
}
.fold svg{ width:100%; height:100%; display:block; }

/* Centred eyebrow / headline / blurb that opens most sections — the
   patterns/section-heading.php cluster. */
.section-heading{ text-align:center; margin:0 0 3.6rem; }
.section-heading > *{ margin-block:0; }

/* Centring the cluster is not enough on its own: core writes
   :root .has-text-align-left onto any block given an alignment, and a
   :root prefix outweighs a lone class, so the child would win. The same
   prefix here matches that weight, and this sheet loads after the block
   library, so the cluster keeps its centre. render.php strips the class
   as well — this is the half that also covers the team block's cluster. */
:root .section-heading > *{ text-align:center; }
.section-heading .eyebrow{ margin:0 0 0.8rem; }
.section-heading h2 strong{ color:var(--bone-dim); }
.section-heading p:not(.eyebrow){ color:#666; font-weight:300; max-width:44ch; margin:1rem auto 0; }

/* On its own in a band there is nothing below to space away from. */
.section-heading:last-child{ margin-bottom:0; }

/* Key/value rows — opening details, contact details. */
.detail-list{ display:flex; flex-direction:column; gap:1rem; }
.detail-list > *{ margin-block:0; }
.detail-row{ display:flex; gap:1.2rem; font-size:0.92rem; }
.detail-row > *{ margin-block:0; }
.detail-row .k{
  font-size:0.68rem; font-weight:700; letter-spacing:0.14em;
  color:var(--bone-dim); min-width:6.5rem; padding-top:0.15rem; flex-shrink:0;
}

@media (max-width:600px){
  .has-pad-top-reduced{  padding-top:2.2rem; }
  .has-pad-top-normal{   padding-top:4rem; }
  .has-pad-top-generous{ padding-top:5rem; }
  .has-pad-bottom-reduced{  padding-bottom:2.2rem; }
  .has-pad-bottom-normal{   padding-bottom:4rem; }
  .has-pad-bottom-generous{ padding-bottom:5rem; }
  :root .has-margin-top-reduced{  margin-top:2.2rem; }
  :root .has-margin-top-normal{   margin-top:4rem; }
  :root .has-margin-top-generous{ margin-top:5rem; }
  :root .has-margin-bottom-reduced{  margin-bottom:2.2rem; }
  :root .has-margin-bottom-normal{   margin-bottom:4rem; }
  :root .has-margin-bottom-generous{ margin-bottom:5rem; }
  .detail-row{ flex-direction:column; gap:0.2rem; }
}

/* =========================================================
   Buttons
   Base look comes from theme.json elements.button; these are the variants
   registered in functions.php via register_block_style().
   ========================================================= */
.wp-block-button__link{
  display:inline-flex; align-items:center; gap:0.5rem;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease),
             border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.wp-block-button__link:hover{ transform:translateY(-2px); }

.wp-block-button.is-style-unfold-outline .wp-block-button__link{
  background:transparent; color:var(--ink); border-color:var(--ink);
}
.wp-block-button.is-style-unfold-outline .wp-block-button__link:hover{
  background:var(--ink); color:var(--paper); border-color:var(--ink);
}
.wp-block-button.is-style-unfold-on-dark .wp-block-button__link{
  background:var(--bone); color:var(--ink); border-color:var(--bone);
}
.wp-block-button.is-style-unfold-on-dark .wp-block-button__link:hover{
  background:var(--paper); color:var(--ink); border-color:var(--paper);
}

/* =========================================================
   Forms
   Only the waitlist capture uses these. They started out beside the
   newsletter pattern; assets/css/holding.css layers the dark-background
   treatment on top, so the base has to outlive any one pattern.
   ========================================================= */
.form-row{ display:flex; gap:0.8rem; justify-content:center; flex-wrap:wrap; margin:0; }
.form-row input[type=email]{
  font-family:inherit; font-size:0.95rem; font-weight:400;
  background:var(--paper); border:1px solid var(--ink); border-radius:999px;
  color:var(--ink); padding:0.85rem 1.4rem; width:280px; max-width:70vw;
}
.form-row input[type=email]::placeholder{ color:#8a8a8a; text-transform:lowercase; }
.form-row input[type=email]:focus-visible{ outline:2px solid var(--ink); outline-offset:2px; }
/* The submit is a plain button, so it borrows the theme.json button element
   styles through .wp-element-button and only needs the shared motion. */
.form-row button{
  font-family:inherit; cursor:pointer;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease),
             border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.form-row button:hover{ transform:translateY(-2px); }

/* The honeypot. Taken out of the layout rather than display:none'd, since a
   bot that reads CSS skips the fields it cannot see. */
.unfold-trap{
  position:absolute !important; width:1px; height:1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap;
}

/* =========================================================
   Tones
   Background + text pairings, registered in functions.php via
   register_block_style() on core/group. Drop one on a section band or on
   a .section-heading used standalone; the bone accents inside follow.
   ========================================================= */
.is-style-unfold-tone-paper{ background:var(--paper); color:var(--ink); }
.is-style-unfold-tone-ink{   background:var(--ink);   color:var(--paper); }
.is-style-unfold-tone-bone{  background:var(--bone);  color:var(--ink); }

/* A tone on the cluster itself turns it into its own band, so it has to
   carry the padding the section wrapper would otherwise have given it. */
.section-heading.is-style-unfold-tone-ink,
.section-heading.is-style-unfold-tone-bone{ padding:3.6rem 6vw; }

/* --- on ink --- */
.is-style-unfold-tone-ink .section-heading .eyebrow,
.section-heading.is-style-unfold-tone-ink .eyebrow{ color:var(--bone); }
.is-style-unfold-tone-ink .section-heading h2 strong,
.section-heading.is-style-unfold-tone-ink h2 strong{ color:var(--bone); }
.is-style-unfold-tone-ink .section-heading p:not(.eyebrow),
.section-heading.is-style-unfold-tone-ink p:not(.eyebrow){ color:rgba(255,255,255,0.68); }

/* --- on bone --- bone accents would vanish, so the emphasis goes to ink. */
.is-style-unfold-tone-bone .section-heading .eyebrow,
.section-heading.is-style-unfold-tone-bone .eyebrow{ color:var(--ink); opacity:0.65; }
.is-style-unfold-tone-bone .section-heading h2 strong,
.section-heading.is-style-unfold-tone-bone h2 strong{ color:var(--ink); font-weight:700; }
.is-style-unfold-tone-bone .section-heading p:not(.eyebrow),
.section-heading.is-style-unfold-tone-bone p:not(.eyebrow){ color:var(--ink); opacity:0.75; }

/* A .section-heading used standalone is its own band, so it answers to the
   spacing scale by hand rather than through the block controls. */
.section-heading.has-pad-bottom-none{ padding-bottom:0; }
.section-heading.has-pad-top-none{ padding-top:0; }

/* =========================================================
   Header / nav
   ========================================================= */
.site-header{
  position:fixed; top:0; left:0; right:0; z-index:100;
  background:var(--paper);
  border-bottom:1px solid var(--line);
}
.site-header .header-inner{ padding:1.35rem 6vw; gap:1.5rem; }

.site-header .wp-block-navigation{
  font-size:0.85rem; font-weight:500;
}
.site-header .wp-block-navigation .wp-block-navigation__container{ gap:2.3rem; }
.site-header .wp-block-navigation-item__content{ position:relative; }
.site-header .wp-block-navigation-item__content::after{
  content:''; position:absolute; left:0; right:0; bottom:-5px; height:2px;
  background:currentColor; transform:scaleX(0); transform-origin:right;
  transition:transform .4s var(--ease);
}
.site-header .wp-block-navigation-item__content:hover::after{ transform:scaleX(1); transform-origin:left; }
/* No underline sweep inside the mobile overlay */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after{ display:none; }
.wp-block-navigation__responsive-container.is-menu-open{ padding:6rem 2rem 2rem; text-align:center; }
/* The nav is justified right for desktop and core reuses that in the overlay.
   The inner list carries .wp-block-navigation.items-justified-right too, so
   it has to be reset on the list itself, not just inherited. */
.wp-block-navigation__responsive-container.is-menu-open,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container{
  --navigation-layout-justification-setting:center;
  --navigation-layout-justify:center;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content{
  justify-content:center; align-items:center;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container{ gap:2rem; font-size:1.1rem; }

/* Buttons nested in the nav block only appear in the mobile overlay. */
.wp-block-navigation__responsive-container:not(.is-menu-open) .nav-overlay-actions{ display:none; }
.is-menu-open .nav-overlay-actions{ margin-top:3rem; gap:0.8rem; width:min(100%, 18rem); }
.is-menu-open .nav-overlay-actions .wp-block-button,
.is-menu-open .nav-overlay-actions .wp-block-button__link{ width:100%; justify-content:center; }
.is-menu-open .nav-overlay-actions .is-style-unfold-outline .wp-block-button__link{
  color:var(--paper); border-color:var(--paper);
}
.is-menu-open .nav-overlay-actions .is-style-unfold-outline .wp-block-button__link:hover{
  background:var(--paper); color:var(--ink);
}

.nav-actions{ display:flex; align-items:center; gap:0.7rem; flex-wrap:nowrap; }
.nav-actions .wp-block-button__link{ padding:0.7rem 1.3rem; font-size:0.76rem; white-space:nowrap; }

/* Below core's 600px overlay breakpoint the nav collapses to a hamburger;
   move it after the buttons so it sits at the far right. Direct child only:
   the list inside the overlay also has the .wp-block-navigation class. */
@media (max-width:599px){
  .site-header .header-right > .wp-block-navigation{ order:1; }
}

/* Section styles live beside the pattern that uses them, in
   patterns/<name>.css — loaded by unfold_pattern_stylesheets(). */

/* =========================================================
   Footer
   ========================================================= */
.site-footer{ background:var(--ink); color:rgba(255,255,255,0.65); padding:5rem 0 2rem; }
.footer-top{ display:grid; grid-template-columns:1.4fr 1fr 1fr 1fr; gap:3rem; padding-bottom:3.5rem; border-bottom:1px solid var(--line-lt); }
.site-footer .logo{ color:var(--paper); margin-bottom:1.1rem; }
.site-footer .logo .word b{ color:var(--bone); }
.site-footer .wp-block-site-logo{ margin-bottom:1.1rem; }
.site-footer .foot-blurb{ font-size:0.92rem; max-width:28ch; font-weight:300; color:rgba(255,255,255,0.55); margin:0; }
.site-footer h4{ font-size:0.7rem; letter-spacing:0.16em; font-weight:700; color:var(--bone); margin:0 0 1.2rem; }
.site-footer ul{ list-style:none; display:flex; flex-direction:column; gap:0.7rem; font-size:0.9rem; margin:0; padding:0; }
.site-footer ul a{ transition:color .3s; }
.site-footer ul a:hover{ color:var(--paper); }
.footer-bottom{ display:flex; justify-content:space-between; align-items:center; padding-top:1.8rem; font-size:0.72rem; font-weight:500; flex-wrap:wrap; gap:1rem; }
.footer-bottom p{ margin:0; }

/* =========================================================
   Interior templates — archives, singles, pages, search
   ========================================================= */
.page-shell{ padding-top:var(--header-h); }

.page-head{ text-align:center; padding:5rem 0 3rem; }
.page-head .eyebrow{ display:block; margin-bottom:0.8rem; }
.page-head h1,
.page-head .wp-block-query-title,
.page-head .wp-block-post-title{ font-size:clamp(2rem,4vw,3.2rem); margin:0; }
.page-head p:not(.eyebrow){ color:#666; font-weight:300; max-width:46ch; margin:1rem auto 0; }

/* Prose measure for the contained templates only.
   core/post-content always stamps .entry-content on its output, whether
   or not the template asked for the class, so an unscoped rule here also
   clamps page-full-width.html — where the sections are meant to run edge
   to edge. .page-shell is the wrapper page.html and single.html share and
   page-full-width.html deliberately lacks. */
.page-shell .entry-content{ max-width:68ch; margin:0 auto; font-weight:300; color:#333; }
.page-shell .entry-content > *{ margin-bottom:1.2rem; }
.page-shell .entry-content h2{ font-size:1.6rem; margin:2.4rem 0 1rem; color:var(--ink); }
.page-shell .entry-content h3{ font-size:1.25rem; margin:2rem 0 0.8rem; color:var(--ink); }
.page-shell .entry-content a{ border-bottom:1px solid var(--bone-dim); }

.post-list{ display:grid; grid-template-columns:repeat(3,1fr); gap:2.4rem; }
.post-list .wp-block-post-title{ font-size:1.15rem; margin:1rem 0 0.4rem; }
.post-list .wp-block-post-excerpt{ font-size:0.88rem; color:#666; font-weight:300; }
.post-list .wp-block-post-featured-image{ aspect-ratio:4/3; overflow:hidden; border-radius:4px; }
.post-list .wp-block-post-featured-image img{ width:100%; height:100%; object-fit:cover; filter:grayscale(1) contrast(1.15) brightness(0.9); }

.pagination-row{ margin-top:4rem; text-align:center; font-size:0.85rem; font-weight:600; }
.pagination-row .wp-block-query-pagination{ justify-content:center; gap:1.2rem; }

/* =========================================================
   Responsive
   ========================================================= */
@media (max-width:980px){
  .post-list{ grid-template-columns:1fr; max-width:520px; margin:0 auto; }
  .footer-top{ grid-template-columns:1fr 1fr; }
}

@media (max-width:760px){
  .site-header .header-inner{ padding:1rem 6vw; }
  .nav-actions .hide-on-mobile{ display:none; }
  .footer-top{ grid-template-columns:1fr; gap:2.2rem; }
}

/* =========================================================
   Editor-only corrections
   ========================================================= */
.editor-styles-wrapper .site-header{ position:relative; }
.editor-styles-wrapper .reveal{ opacity:1; transform:none; }
