/* ==========================================================================
   Ladushi — layout.css
   Containers, the 12-column grid, page chrome (header, menu, footer).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Containers & sections
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow { max-width: 64rem; }
.container--prose  { max-width: var(--measure); }
.container--full   { max-width: none; }

.section {
  position: relative;
  padding-block: var(--section-y);
}

.section--tight { padding-block: calc(var(--section-y) * .55); }
.section--flush-top { padding-block-start: 0; }
.section--flush-bottom { padding-block-end: 0; }

.section--sunken { background-color: var(--c-bg-sunken); }
.section--raised { background-color: var(--c-bg-raised); }

/* A hairline that reads as a seam between sections rather than a border. */
.section--seam { border-block-start: var(--border); }

/* --------------------------------------------------------------------------
   2. Grid
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--s-6) var(--gutter);
}

/* Spans set only the END line, never the shorthand. `grid-column: span 7`
   would expand to `grid-column-start: span 7; grid-column-end: auto`, and a
   companion `.start-5` would then overwrite that start and leave the element
   spanning a single column. Setting the end line lets the two compose. */
.col-1  { grid-column-end: span 1; }
.col-2  { grid-column-end: span 2; }
.col-3  { grid-column-end: span 3; }
.col-4  { grid-column-end: span 4; }
.col-5  { grid-column-end: span 5; }
.col-6  { grid-column-end: span 6; }
.col-7  { grid-column-end: span 7; }
.col-8  { grid-column-end: span 8; }
.col-9  { grid-column-end: span 9; }
.col-10 { grid-column-end: span 10; }
.col-11 { grid-column-end: span 11; }
.col-12 { grid-column-end: span 12; }

.start-2 { grid-column-start: 2; }
.start-3 { grid-column-start: 3; }
.start-4 { grid-column-start: 4; }
.start-5 { grid-column-start: 5; }
.start-7 { grid-column-start: 7; }
.start-8 { grid-column-start: 8; }

/* Below the lg breakpoint every column runs the full row. Both the span and
   the start utilities resolve to the same start line so the result does not
   depend on which class the author listed first. */
@media (max-width: 60rem) {
  .grid { gap: var(--s-6); }
  .col-1, .col-2, .col-3, .col-4, .col-5,
  .col-6, .col-7, .col-8, .col-9, .col-10, .col-11 {
    grid-column-start: 1;
    grid-column-end: -1;
  }
  .start-2, .start-3, .start-4, .start-5, .start-7, .start-8 {
    grid-column-start: 1;
  }
  .col-md-6 {
    grid-column-start: auto;
    grid-column-end: span 6;
  }
}

/* One track rather than twelve collapsed ones. The tracks themselves shrink
   to nothing on a phone, but the eleven gaps between them do not: the rule
   above sets the shorthand, so the column gap is 2rem apiece and they total
   22rem — wider than the content box of a 360px screen. The grid then sits
   wider than the viewport it lives in, the section runs off the right edge
   and its text is pushed into the gutter. With a single column there are no
   gaps left to add up. Every item here already spans the full row, so the
   twelve tracks were carrying nothing. */
@media (max-width: 40rem) {
  .grid { grid-template-columns: minmax(0, 1fr); }

  .col-md-6 {
    grid-column-start: 1;
    grid-column-end: -1;
  }
}

/* Simple flow utilities used inside grid cells. */
.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-block-start: var(--flow, var(--s-4)); }
.stack--sm { --flow: var(--s-3); }
.stack--lg { --flow: var(--s-6); }
.stack--xl { --flow: var(--s-8); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
}

.cluster--between { justify-content: space-between; }
.cluster--gap-lg { gap: var(--s-5); }

/* --------------------------------------------------------------------------
   3. Header
   -------------------------------------------------------------------------- */

/* Frosted rather than painted. What separates the bar from the film is the
   blur, not the opacity — a heavy tint reads as a white slab and hides the
   footage, while a light tint over a strong blur stays legible even when the
   frame behind it is a similar tone. The hairline does the rest. */
.site-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-header);
  padding-block: var(--s-4);
  background-color: rgba(253, 252, 250, .62);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  border-block-end: var(--border);
  transition: transform var(--d-base) var(--e-out),
              background-color var(--d-base) var(--e-out),
              padding var(--d-base) var(--e-out);
}

/* Once real content is behind it rather than the film, firm it up so text
   never scrolls through the bar. */
.site-header.is-condensed { background-color: rgba(253, 252, 250, .86); }

/* No backdrop-filter support means the tint is all there is, so it has to
   carry the bar on its own. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background-color: rgba(253, 252, 250, .92); }
}

/* Condensed state: the same bar, tightened. */
.site-header.is-condensed { padding-block: var(--s-2); }

/* The overlay menu is stacked above the header, which would otherwise bury
   the control used to close it. */
body.is-menu-open .site-header { z-index: calc(var(--z-menu) + 1); }

/* Hidden while scrolling down, revealed on scroll up. */
.site-header.is-hidden { transform: translateY(-101%); }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  text-decoration: none;
  white-space: nowrap;
}

.brand__mark {
  width: auto;
  height: 2.75rem;
  flex: none;
  transition: height var(--d-base) var(--e-out),
              transform var(--d-base) var(--e-out);
}

.brand:hover .brand__mark { transform: scale(1.05); }

.brand__wordmark {
  width: auto;
  height: 2.5rem;
  flex: none;
  transition: height var(--d-base) var(--e-out);
}

/* Tighten the lockup once the header shrinks. */
.site-header.is-condensed .brand__mark { height: 2.25rem; }
.site-header.is-condensed .brand__wordmark { height: 2rem; }

/* The footer lockup is left-aligned in its column, and must not shrink: as a
   flex item beside the standfirst it was being compressed, squashing the eye. */
.site-footer .brand {
  align-items: flex-start;
  flex: none;
}

/* The standfirst reads as a closing statement, not as body copy — it takes
   the display face like the headings it echoes. */
.site-footer__brand .lead {
  font-family: var(--font-display);
  font-size: var(--t-md);
  line-height: var(--lh-normal);
  letter-spacing: var(--tr-snug);
  color: var(--c-fg);
  max-width: 26rem;
}

@media (max-width: 40rem) {
  .brand__mark { height: 2.5rem; }
  .brand__wordmark { height: 2.1rem; }
}

/* Desktop navigation ------------------------------------------------------ */

.nav {
  display: flex;
  align-items: center;
  gap: var(--s-6);
}

@media (max-width: 56rem) {
  .nav { display: none; }
}

.nav__link {
  position: relative;
  font-size: var(--t-sm);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--c-fg);
  padding-block: var(--s-2);
  transition: color var(--d-fast) var(--e-out);
}

.nav__link::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  width: 100%;
  height: 1px;
  background-color: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--d-base) var(--e-out);
}

.nav__link:hover,
.nav__link:focus-visible { color: var(--c-fg); }

.nav__link:hover::after,
.nav__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

.nav__link[aria-current="page"] {
  color: var(--c-fg);
}

.nav__link[aria-current="page"]::after {
  transform: scaleX(1);
  background-color: var(--c-accent);
}


.header-actions {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

/* Menu toggle — only shown where the inline nav is not. */
/* The hairline border alone vanished against the frosted bar over bright
   footage. It needs a ground of its own to read as a control. */
.menu-toggle {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius-pill);
  background-color: rgba(253, 252, 250, .72);
  backdrop-filter: blur(10px) saturate(150%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  color: var(--c-fg);
  transition: border-color var(--d-fast) var(--e-out),
              background-color var(--d-fast) var(--e-out);
}

.menu-toggle:hover { background-color: rgba(253, 252, 250, .92); }

.menu-toggle:hover { border-color: var(--c-line-strong); }

@media (max-width: 56rem) {
  .menu-toggle { display: inline-flex; }
}

.menu-toggle__bars {
  display: block;
  position: relative;
  width: 1.125rem;
  height: 0.625rem;
}

.menu-toggle__bars::before,
.menu-toggle__bars::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 1px;
  background-color: currentColor;
  transition: transform var(--d-base) var(--e-out);
}

.menu-toggle__bars::before { top: 0; }
.menu-toggle__bars::after  { bottom: 0; }

.menu-toggle[aria-expanded="true"] .menu-toggle__bars::before {
  transform: translateY(0.3125rem) rotate(45deg);
}

.menu-toggle[aria-expanded="true"] .menu-toggle__bars::after {
  transform: translateY(-0.3125rem) rotate(-45deg);
}

/* --------------------------------------------------------------------------
   4. Overlay menu
   -------------------------------------------------------------------------- */

.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  justify-content: center;
  background-color: var(--c-bg);
  padding: var(--s-12) var(--gutter) var(--s-8);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--d-base) var(--e-out),
              visibility 0s linear var(--d-base);
}

.menu.is-open {
  visibility: visible;
  opacity: 1;
  transition: opacity var(--d-base) var(--e-out), visibility 0s;
}

.menu__list {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.menu__item {
  overflow: hidden;
}

.menu__link {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
  text-decoration: none;
  padding-block: var(--s-2);
  transform: translateY(110%);
  transition: transform var(--d-slow) var(--e-out), color var(--d-fast) var(--e-out);
}

.menu.is-open .menu__link { transform: translateY(0); }

/* Stagger each row in behind the one above it. */
.menu__item:nth-child(1) .menu__link { transition-delay: 60ms; }
.menu__item:nth-child(2) .menu__link { transition-delay: 110ms; }
.menu__item:nth-child(3) .menu__link { transition-delay: 160ms; }
.menu__item:nth-child(4) .menu__link { transition-delay: 210ms; }
.menu__item:nth-child(5) .menu__link { transition-delay: 260ms; }

.menu__link:hover { color: var(--c-accent); }

.menu__link[aria-current="page"] { color: var(--c-accent); }

.menu__index {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--c-fg-faint);
  margin-inline-end: var(--s-4);
  vertical-align: super;
}

.menu__footer {
  margin-block-start: auto;
  padding-block-start: var(--s-8);
  border-block-start: var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
  justify-content: space-between;
  color: var(--c-fg-muted);
  font-size: var(--t-sm);
}

/* Body lock while the overlay is open. */
body.is-menu-open { overflow: hidden; }

/* --------------------------------------------------------------------------
   5. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  position: relative;
  background-color: var(--c-bg-sunken);
  border-block-start: var(--border);
  padding-block: var(--s-11) var(--s-6);
}

.site-footer__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--s-8) var(--gutter);
}

/* Symbol and standfirst read as one unit, side by side. */
.site-footer__brand {
  grid-column: span 5;
  display: flex;
  align-items: center;
  gap: var(--s-5);
}

.site-footer__brand .lead { max-width: 26rem; }

@media (max-width: 34rem) {
  .site-footer__brand { gap: var(--s-4); }
}
.site-footer__col   { grid-column: span 2; }
.site-footer__col--wide { grid-column: span 3; }

@media (max-width: 60rem) {
  .site-footer__brand { grid-column: span 12; }
  .site-footer__col,
  .site-footer__col--wide { grid-column: span 6; }
}

@media (max-width: 34rem) {
  .site-footer__col,
  .site-footer__col--wide { grid-column: span 12; }
}

@media (max-width: 48rem) {
  .site-footer { padding-block: var(--s-9) var(--s-5); }
  .site-footer__grid { gap: var(--s-7) var(--gutter); }
  .site-footer__bottom { margin-block-start: var(--s-6); }
}

.site-footer__heading {
  font-family: var(--font-body);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: var(--tr-wider);
  text-transform: uppercase;
  color: var(--c-fg-faint);
  margin-block-end: var(--s-4);
}

.site-footer__links {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.site-footer__links a {
  text-decoration: none;
  color: var(--c-fg-muted);
  font-size: var(--t-sm);
  transition: color var(--d-fast) var(--e-out);
  width: fit-content;
}

.site-footer__links a:hover { color: var(--c-fg); }

.site-footer__bottom {
  margin-block-start: var(--s-7);
  padding-block-start: var(--s-5);
  border-block-start: var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  justify-content: space-between;
  align-items: center;
  font-size: var(--t-xs);
  color: var(--c-fg-faint);
  letter-spacing: var(--tr-wide);
}

/* The only wordmark in the footer — the masthead above it carries the eye
   alone. Kept in flow rather than absolutely positioned: it then reserves its
   own height, and a negative top margin is what tucks it up behind the
   columns. Absolute positioning gave the footer nothing to reserve, so the
   mark landed straight on top of the blurb. */
.footer-wordmark {
  position: relative;
  z-index: 0;
  width: min(34rem, 52%);
  margin-block: -5.5rem 0;
  margin-inline: 0;
  overflow: visible;
  pointer-events: none;
}

.footer-wordmark img {
  display: block;
  width: 100%;
  height: auto;
  filter: grayscale(1);
  opacity: .3;
}

/* Content sits above the watermark. */
.site-footer__grid,
.site-footer__bottom { position: relative; z-index: 1; }

/* The masthead carries the symbol on its own, so it can be larger. */
.site-footer .brand__mark { height: 4.5rem; }

/* Stacked, the columns fill the width, so there is no empty space beside them
   for the mark to sit behind. It is lifted out of flow and parked over the
   masthead instead — the eye and standfirst are the one place with room, and
   the grid above it (z-index 1) keeps the copy legible.
   Placed after the base rule on purpose: a media query adds no specificity,
   so a later base declaration would simply win. */
@media (max-width: 48rem) {
  .site-footer .container { position: relative; }

  .footer-wordmark {
    position: absolute;
    inset-block-start: var(--s-1);
    inset-inline-start: 0;
    margin: 0;
    width: min(19rem, 80%);
  }

  .footer-wordmark img { opacity: .34; }

  .site-footer .brand__mark { height: 3.5rem; }
}

/* --------------------------------------------------------------------------
   6. Page transition veil
   -------------------------------------------------------------------------- */

.veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-transition);
  background-color: var(--c-bg);
  pointer-events: none;
  transform: scaleY(0);
  transform-origin: bottom;
}

.veil.is-covering {
  pointer-events: all;
  transform: scaleY(1);
  transform-origin: bottom;
  transition: transform var(--d-slow) var(--e-in-out);
}

.veil.is-revealing {
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--d-slow) var(--e-in-out);
}

/* --------------------------------------------------------------------------
   7. Custom cursor — the brand eye, pointer-fine devices only

   The pupil is pinned to the exact pointer position while the eye outline
   trails behind it, so during movement the eye reads as looking toward the
   cursor and settles into the complete mark when the pointer stops.
   -------------------------------------------------------------------------- */

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-cursor);
  pointer-events: none;
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .cursor { display: block; }
}

.cursor__dot,
.cursor__ring {
  position: absolute;
  transform: translate(-50%, -50%);
}

/* The pupil. Grows with the eye so the proportion between them holds —
   the eye opens 1.45x on hover and the pupil tracks it. */
.cursor__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--c-indigo);
  transition: width var(--d-base) var(--e-out),
              height var(--d-base) var(--e-out);
}

.cursor__ring {
  display: block;
  width: 58px;
  height: 58px;
  transition: width var(--d-base) var(--e-out),
              height var(--d-base) var(--e-out);
}

.cursor__ring svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.cursor__lid {
  fill: none;
  stroke: var(--c-indigo);
  stroke-width: 2;
  stroke-linejoin: round;
  /* Keeps the line weight constant as the eye scales open. */
  vector-effect: non-scaling-stroke;
}

/* Stars stay out of the way until there is something to click. */
.cursor__stars {
  fill: var(--c-accent);
  opacity: 0;
  transform: scale(.62) rotate(-14deg);
  transform-origin: 32px 32px;
  transition: opacity var(--d-base) var(--e-out),
              transform var(--d-slow) var(--e-spring);
}

.cursor.is-hovering .cursor__ring {
  width: 76px;
  height: 76px;
}

.cursor.is-hovering .cursor__dot {
  width: 12px;
  height: 12px;
}

.cursor.is-hovering .cursor__stars {
  opacity: 1;
  transform: scale(1) rotate(0deg);
}

@media (prefers-reduced-motion: reduce) {
  .cursor { display: none !important; }
}

/* --------------------------------------------------------------------------
   8. Scroll progress rail
   -------------------------------------------------------------------------- */

/* The rail is painted from the first frame. With a transparent track and a
   bar that starts at scaleX(0), nothing at all was drawn at scroll 0 — the
   gold only appeared once you had moved a few pixels, which read as a bar
   that failed to load rather than a progress indicator at zero. */
.scroll-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  z-index: calc(var(--z-header) + 1);
  background-color: var(--c-line-strong);
  pointer-events: none;
}

.scroll-progress__bar {
  height: 100%;
  width: 100%;
  background-color: var(--c-accent);
  transform: scaleX(0);
  transform-origin: left;
}
