/* ============================================================
   THE COMPACT INSTITUTE - Scroll-driven experience
   Reversed flow: Book format → Explore dimensions → Book format
   ============================================================ */

@font-face {
  font-family: 'Montas';
  src: url('../assets/Montas-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root{
  /* The design is a fixed 1440x900 canvas, so the unit has to answer to BOTH
     axes -- keyed to width alone, a short window scaled nothing and simply cut
     the artwork off at the bottom. min() makes the whole composition shrink to
     fit whichever axis is tighter. At exactly 1440x900 both terms equal 1px, so
     the tuned proportions are unchanged. */
  --u: min(calc(100vw / 1440), calc(100vh / 900));
  --paper:  #ECECEC;
  --ink:    #1C1A16;
  --ink-soft: #57544A;   /* secondary text: eyebrows, bylines, captions */
  --card:   #FFFFFF;     /* fill for anything that sets itself apart from the page */
  --line:   #1C1A16;
  --green:  #628C69;
  --serif: 'Montas', ui-serif, Georgia, serif;
}

*{ margin:0; padding:0; box-sizing:border-box; }

html{
  scroll-behavior: smooth;
}

body{
  background: var(--paper);
  font-family: var(--serif);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* paper grain overlay */
.grain{
  position: fixed; inset: 0;
  background-image: url("../assets/grain.png");
  background-repeat: repeat;
  background-size: calc(180 * var(--u)) calc(180 * var(--u));
  pointer-events: none;
  z-index: 9000;
}

/* ----------------------------------------------------------
   SCROLL CONTAINER
   ---------------------------------------------------------- */
.scroll-container{
  position: relative;
}

/* Spacer sits BEFORE the stage and supplies the animation's scroll distance.
   Animation length = spacer height - 100vh. */
.scroll-spacer{
  height: 400vh;
  pointer-events: none;
}

/* ----------------------------------------------------------
   STAGE
   Pinned for the entire page. The masthead, statement, artwork
   and grid never move; in the end state each column's copy
   scrolls independently under its own tab header.
   ---------------------------------------------------------- */
.stage{
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

/* ----------------------------------------------------------
   RULES (horizontal lines)
   ---------------------------------------------------------- */
.rule{
  position: absolute;
  left: 0;
  width: 100vw;
  height: calc(1.5 * var(--u));
  background: var(--line);
  opacity: .82;
  z-index: 5;
}
/* Clear of the logo's bottom edge, which is at 79u (12u top + 67u tall) */
.rule--head-bot{ top: calc(90 * var(--u)); }

/* Section rule - visible in book states (default), hidden when exploring */
.rule--section{
  top: calc(355 * var(--u));
  opacity: .82;
  transition: opacity 0.4s ease;
}
.stage.exploring .rule--section{
  opacity: 0;
}

/* Vertical rules - visible in book states, hidden when exploring */
.vrule{
  position: absolute;
  top: calc(355 * var(--u));
  bottom: 0;
  width: calc(1.5 * var(--u));
  background: var(--line);
  opacity: .82;
  z-index: 6;
  transition: opacity 0.4s ease;
}
.stage.exploring .vrule{
  opacity: 0;
}
.vrule--1{ left: calc(300 * var(--u)); }
.vrule--2{ left: calc(600 * var(--u)); }
.vrule--3{ left: calc(900 * var(--u)); }

/* ----------------------------------------------------------
   HEADER
   ---------------------------------------------------------- */
.masthead{
  position: absolute;
  left: 0; right: 0;
  top: calc(12 * var(--u));
  height: calc(67 * var(--u));
  display: flex;
  align-items: center;
  z-index: 100;
}

.mark{
  position: absolute;
  left: calc(56 * var(--u));
  top: 0;
  width: calc(67 * var(--u));
  height: calc(67 * var(--u));
  display: block;
}
.mark img{ width: 100%; height: 100%; display: block; }

.wordmark{
  position: absolute;
  left: calc(158 * var(--u));
  font-size: calc(26 * var(--u));
  line-height: 1;
  letter-spacing: calc(3.1 * var(--u));
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.nav{
  position: absolute;
  right: calc(40 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(60 * var(--u));
}
.nav a{
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: calc(4.3 * var(--u));
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  transition: opacity .18s ease;
}
.nav a:hover{ opacity: .55; }

/* ----------------------------------------------------------
   STATEMENT
   ---------------------------------------------------------- */
.statement{
  position: absolute;
  left: calc(56 * var(--u));
  right: calc(56 * var(--u));
  top: calc(140 * var(--u));
  z-index: 2;
  opacity: 1;
  transition: opacity 0.4s ease;
}
.statement p{
  font-size: calc(32 * var(--u));
  line-height: 1.4;
  margin: 0 0 calc(28 * var(--u)) 0;
}
.statement p:last-child{
  margin-bottom: 0;
}

/* A link inside display-size text: the underline is set thin and offset far
   enough not to crowd the descenders at this size. */
.statement a{
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: calc(1.5 * var(--u));
  text-underline-offset: calc(6 * var(--u));
  transition: color .18s ease;
}
.statement a:hover{ color: var(--green); }

/* The statement belongs to the book format. It clears out while exploring so
   the vertically centred dimension text has the right side to itself -- the
   opacity transition above was authored for exactly this and never fired. */
.stage.exploring .statement{
  opacity: 0;
}

/* ----------------------------------------------------------
   ORBIT - display and dimension images
   Default: book format (right side)
   Exploring: centered
   ---------------------------------------------------------- */
.orbit{
  position: absolute;
  /* Above .vrule (6) so the artwork occludes the grid line where it bleeds
     into the Blogs column. Below .columns (10) so tabs stay on top. */
  z-index: 7;
  /* Book format: display.png has 13.3% left pad / 69.9% artwork width.
     Values solved so visible artwork spans 850->1420px:
     width 815 * 0.699 = 570px art; left 742 + (815 * 0.133) = 850px art start.
     Top compensated for taller image box so artwork stays put vertically. */
  left: calc(742 * var(--u));
  top: calc(331 * var(--u));
  width: calc(815 * var(--u));
  /* Every child is absolutely positioned, so without this the box measures zero
     high and translateY(-50%) resolves to nothing -- the artwork then hangs down
     from the centring line instead of straddling it. Matches the source images. */
  aspect-ratio: 1440 / 1024;
  transform: translate(0, 0);
  transition: left 0.6s ease, top 0.6s ease, width 0.6s ease, transform 0.6s ease;
}

/* Exploring: the artwork takes a little over half the width, centred in that
   left region (29% == the midpoint of 0-58%), leaving the right side to the
   dimension text. Percent rather than units so the split holds even when --u is
   height-constrained. */
.stage.exploring .orbit{
  left: 29%;
  top: 50vh;
  width: calc(820 * var(--u));
  transform: translate(-50%, -50%);
}

/* Shape-only occlusion: paper texture painted ONLY where display.png has alpha.
   Hides the vertical rule behind the artwork shapes while leaving it visible
   in the gaps between them. */
.orbit__backing{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  aspect-ratio: 1440 / 1024;
  /* Flat paper, not a texture image: the global .grain overlay (z 9000) already
     paints texture over this, so a second texture would double up and read
     lighter than the page. display-mask.png is a filled silhouette of the
     artwork -- display.png itself is a hatch with no opaque pixels, so it
     cannot mask anything. */
  background: var(--paper);
  -webkit-mask-image: url('../assets/display-mask.png');
  mask-image: url('../assets/display-mask.png');
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

/* Backing only serves the book states, where vrules are visible */
.stage.exploring .orbit__backing{
  opacity: 0;
}

.orbit__img{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: auto;
  transition: opacity 0.3s ease;
}

#orbit-display{
  opacity: 1;
}
#orbit-display.dimmed{
  opacity: 0.32;
}

.orbit__dimension{
  opacity: 0;
  pointer-events: none;
}
.orbit__dimension.active{
  opacity: 1;
}

/* ----------------------------------------------------------
   DIMENSION TEXT
   Occupies the right side opposite the artwork, centred on the
   viewport midline so the two halves read as a pair whatever
   the length of the copy.
   ---------------------------------------------------------- */
.dim-text{
  position: fixed;
  left: 60%;
  right: calc(56 * var(--u));
  top: 50%;
  transform: translateY(-50%);
  z-index: 200;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
.dim-text.active{
  opacity: 1;
}

/* Montas ships in a single Regular weight, so this is a synthesised bold. The
   size step carries most of the hierarchy; the weight is a secondary cue. */
.dim-text__title{
  font-size: calc(38 * var(--u));
  line-height: 1.2;
  font-weight: 700;
  margin: 0 0 calc(24 * var(--u)) 0;
}

.dim-text__body{
  font-size: calc(20 * var(--u));
  line-height: 1.55;
  margin: 0;
}

/* ----------------------------------------------------------
   COLUMNS - contain tabs and content
   Default: book format (at section line)
   Exploring: tabs at bottom
   ---------------------------------------------------------- */
.columns{
  position: absolute;
  z-index: 10;
  left: 0;
  width: calc(1200 * var(--u));
  /* Default: at section line */
  top: calc(355 * var(--u));
  bottom: 0;
  transition: top 0.6s ease, bottom 0.6s ease;
}

.stage.exploring .columns{
  /* Exploring: just tabs at bottom with more padding */
  top: auto;
  bottom: calc(80 * var(--u));
  height: auto;
}

/* Horizontal rule above tabs during exploring - match book format spacing (12px gap via tab margin) */
.rule--tabs{
  position: absolute;
  left: 0;
  width: 100vw;
  height: calc(1.5 * var(--u));
  background: var(--line);
  opacity: 0;
  z-index: 11;
  /* Position at top of tab boxes: bottom 80 + tab ~50 + margin 12 = 142, minus margin for same spacing */
  bottom: calc(92 * var(--u));
  transition: opacity 0.4s ease;
}
.stage.exploring .rule--tabs{
  opacity: .82;
}

/* Column dividers during exploring - run from the tab rule down to the page
   edge, echoing the grid from the book states */
.vrule--tabs{
  position: absolute;
  bottom: 0;
  height: calc(92 * var(--u));
  width: calc(1.5 * var(--u));
  background: var(--line);
  opacity: 0;
  z-index: 11;
  transition: opacity 0.4s ease;
}
.stage.exploring .vrule--tabs{
  opacity: .82;
}
.vrule--tabs--1{ left: calc(300 * var(--u)); }
.vrule--tabs--2{ left: calc(600 * var(--u)); }
.vrule--tabs--3{ left: calc(900 * var(--u)); }

/* Column structure */
.column{
  position: absolute;
  top: 0;
  bottom: 0;
  width: calc(300 * var(--u));
  display: flex;
  flex-direction: column;
}
.column--1{ left: 0; }
.column--2{ left: calc(300 * var(--u)); }
.column--3{ left: calc(600 * var(--u)); }
.column--4{ left: calc(900 * var(--u)); }

/* Tab headers */
.tab{
  display: inline-block;
  margin: calc(12 * var(--u)) 0 0 calc(13 * var(--u));
  padding: calc(8 * var(--u)) calc(12 * var(--u));
  font-size: calc(22 * var(--u));
  line-height: 1.3;
  letter-spacing: calc(2 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--line);
  background: var(--paper);
  text-decoration: none;
  color: var(--ink);
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
  align-self: flex-start;
}
.tab:hover{
  background: var(--green);
  color: #f4f4f0;
  border-color: var(--green);
}

/* Column content (placeholder text).
   The outer box clips, the inner box travels: copy scrolling upward vanishes at
   the top edge of the content area, so it reads as passing under the tab row
   rather than colliding with it. */
.column-content{
  flex: 1;
  overflow: hidden;
  font-size: calc(18 * var(--u));
  line-height: 1.5;
  color: var(--ink);
  opacity: 1;
  transition: opacity 0.4s ease;
  /* The clip edge sits flush against the tab's bottom border, so a hard cut
     would slice a line of glyphs in half right on the rule. Fading the first
     20u -- exactly the inner padding, so the resting state is untouched --
     lets copy dissolve as it passes under the tab instead. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 calc(20 * var(--u)));
  mask-image: linear-gradient(to bottom, transparent 0, #000 calc(20 * var(--u)));
}
.column-content__inner{
  padding: calc(20 * var(--u)) calc(13 * var(--u));
}

/* In the end state each column becomes its own scroll container, so the three
   bodies of copy move independently instead of in lockstep. Kept off until
   then: while the animation runs, a wheel over a column must advance the page,
   not the text. */
.stage.complete .column-content{
  overflow-y: auto;
}
/* Room for the scrollbar so copy doesn't run under it */
.stage.complete .column-content__inner{
  padding-right: calc(20 * var(--u));
}

/* Styling the scrollbar also opts out of macOS overlay behaviour, so the
   indicator stays visible instead of fading out when idle. Kept hairline and
   faint so it reads as a margin mark rather than browser furniture; it firms up
   on hover, when it is actually being aimed at. */
.stage.complete .column-content::-webkit-scrollbar{
  width: calc(4 * var(--u));
}
.stage.complete .column-content::-webkit-scrollbar-track{
  background: transparent;
}
.stage.complete .column-content::-webkit-scrollbar-thumb{
  background: rgba(28, 26, 22, .18);
}
.stage.complete .column-content::-webkit-scrollbar-thumb:hover{
  background: rgba(28, 26, 22, .40);
}

.stage.exploring .column-content{
  opacity: 0;
}

/* ----------------------------------------------------------
   POST LIST - the Blogs column
   ---------------------------------------------------------- */
.post-list{
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Generous separation so three entries read as three, not as a block */
.post-list__item{
  margin-bottom: calc(40 * var(--u));
}
.post-list__item:last-child{ margin-bottom: 0; }

.post-list__title{
  display: block;
  font-size: calc(22 * var(--u));
  line-height: 1.25;
  color: var(--ink);
  text-decoration: none;
  margin-bottom: calc(7 * var(--u));
  transition: color .18s ease;
}
.post-list__title:hover{ color: var(--green); }

.post-list__standfirst{
  font-size: calc(17 * var(--u));
  line-height: 1.42;
  margin: 0 0 calc(6 * var(--u));
}
.post-list__byline{
  font-size: calc(15 * var(--u));
  line-height: 1.4;
  color: var(--ink-soft);
  margin: 0;
}

/* ----------------------------------------------------------
   SCROLL FADE - gradient at bottom to hint "scroll down"
   Only visible at start (before any scrolling)
   ---------------------------------------------------------- */
.scroll-fade{
  position: absolute;
  bottom: 0;
  left: 0;
  width: calc(900 * var(--u));
  height: calc(200 * var(--u));
  background: linear-gradient(to bottom, transparent 0%, var(--paper) 100%);
  z-index: 20;
  opacity: 1;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* Hidden while exploring, and in the end state too: there the scrollbars are
   the affordance, so the gradient would only veil readable copy. */
.stage.exploring .scroll-fade,
.stage.complete .scroll-fade{
  opacity: 0;
}

/* Complete state is the book format again */
.stage.complete .rule--section{
  opacity: .82;
}
.stage.complete .vrule{
  opacity: .82;
}
.stage.complete .column-content{
  opacity: 1;
}

/* ----------------------------------------------------------
   RESPONSIVE
   ---------------------------------------------------------- */
/* No --u override for narrow windows: re-basing the unit on a 760 canvas while
   the layout is still 1440 units wide is what pushed the columns past the
   viewport edge. The min() unit above already scales the composition down to
   fit, so narrow windows letterbox rather than clip.
   NOTE: this keeps the desktop composition intact at every size rather than
   reflowing it, so on a phone-width window the type gets genuinely small. A
   real mobile layout -- stacked columns, its own type scale -- is separate
   work. */

/* ============================================================
   SUBPAGE CHROME
   Everything except the home experience: a sticky textured
   header, boxed labels, and the paper texture moved BENEATH the
   content. Shared by blog posts and the projects page, so it
   lives here rather than being duplicated per page type.
   ============================================================ */

/* main.css floats .grain above everything at z 9000, which is right for the
   home artwork but means white cards pick the texture up and read as
   translucent. The style guide is explicit that content "always sits in a solid
   white card on top of it", so on subpages the texture goes underneath. */
body.page .grain{
  z-index: -1;
}

/* Must be opaque to cover copy scrolling beneath, but a flat fill left it the
   one band on the page with no paper texture, reading as a solid slab. Since
   .grain now sits below the content and cannot reach it, the header carries the
   grain itself -- same tile and scale. */
.site-head{
  position: sticky;
  top: 0;
  height: calc(104 * var(--u));
  z-index: 500;
  background-color: var(--paper);
  background-image: url("../assets/grain.png");
  background-repeat: repeat;
  background-size: calc(180 * var(--u)) calc(180 * var(--u));
}

/* Boxed label, the home page tab treatment */
.boxed{
  display: inline-block;
  padding: calc(8 * var(--u)) calc(12 * var(--u));
  font-size: calc(19 * var(--u));
  line-height: 1.3;
  letter-spacing: calc(2 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--line);
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
}
