/* ===========================================================================
   Landing page — minimal rebuild (2026-08-11)
   ===========================================================================

   Replaces the car-dashboard/navigation pastiche in studio_landing.html with
   a single quiet screen. The reference the direction came from is
   akicreate.com, which was studied directly rather than eyeballed: its
   measurements are recorded below next to ours so the next person can see
   what was deliberate and what was ours.

   What was taken is the *structure and the interaction*, not the content:

     - one white viewport, nothing scrolls, everything anchored to the four
       corners and the middle
     - a grid of letters in the centre with the name emerging from it in a
       serif, the rest of the grid decorative filler in a light mono
     - hovering any cell re-randomises that whole row; the name letters are
       pinned and never move
     - nav labels roll on hover behind a mask

   Their type is licensed (PP Neue Montreal / Tobias) and is not used here.
   The sans is GiSans, which is Godrej's own brand face and already
   self-hosted for the app; the serif and mono are system stacks, so this
   page adds no font downloads at all.

   Reference measurements, theirs -> ours:
     cell             76px            -> 76px
     grid gap         12.24px         -> 12px
     filler letter    22.5px #c1c1c1  -> 22px  #c1c1c1
     name letter      43px   #313131  -> 44px  #1c1c1e
     body text        16px   #050505  -> 15px  #111113
     muted text       16px   #c3c3c3  -> 15px  #b9b9bd
     page padding     17px            -> 20px (24px on the app's own gutter)
   =========================================================================== */

@font-face {
  font-family: "GiSans Text";
  src: url("../fonts/gisans/GiSansText-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "GiSans Text";
  src: url("../fonts/gisans/GiSansText-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #111113;
  --ink-muted: #b9b9bd;
  /* Between the muted grey and the near-black — see .caption. */
  --ink-caption: #6d6d73;
  --filler: #c1c1c1;
  --name: #1c1c1e;
  --paper: #ffffff;

  --cell: 76px;
  --grid-gap: 12px;

  /* Two sans stacks, and which is which matters.
   *
   * --font-brand is GiSans, Godrej's own face, already self-hosted.
   * --font-ui is the platform face. It is here because GiSans ships no
   *   Light — see the note on .t-muted — and because every label on this
   *   page now sets in it, so the whole frame reads as one voice.
   */
  --font-brand: "GiSans Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* One curve for everything that moves. Decelerating, so a letter arrives
     rather than snapping into place. */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* Flatter and longer, for the one big surface on this page. A fast start on
     something the size of a panel reads as violent. */
  --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);

  /* The cursor strip. --strip-x is written by JS every frame; the other two
     are the design. */
  --r-pill: 9999px;

  --strip-x: 50vw;
  --strip-w: 170px;
  --strip-color: #111113;
  /* Inside the band the page keeps its own hierarchy, it just runs the other
     way round. These three mirror --name / --filler / --ink-caption against
     black, so the name still reads as the loudest thing in the column. */
  --strip-ink: #ffffff;
  --strip-filler: rgb(255 255 255 / 34%);
  --strip-caption: rgb(255 255 255 / 68%);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body.landing {
  margin: 0;
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-brand);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Nothing on this page scrolls. It is one screen by design — the moment it
     scrolls, the corner anchoring that holds the whole layout together stops
     meaning anything. */
  overflow: hidden;
}

/* --- The frame -------------------------------------------------------------
 * A 3x3 grid: the nine slots are the four corners, the four edge-middles and
 * the centre. Every piece of text on this page sits in one of them, which is
 * what makes the composition read as deliberate rather than as a stack that
 * happened to end up centred.
 */
.landing-frame {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-rows: auto 1fr auto;
  width: 100%;
  height: 100dvh;
  padding: 20px 24px;
  gap: 12px;
}

.slot {
  display: flex;
  min-width: 0;
}
.slot-tl { justify-content: flex-start; align-items: flex-start; }
.slot-tc { justify-content: center;     align-items: flex-start; }
.slot-tr { justify-content: flex-end;   align-items: flex-start; }

/* Placed by hand, because the composition lost its corners (2026-08-11) and
 * these two are now the only things in their rows. Auto-placement would drop
 * each of them into column 1 and the whole page would hang off the left
 * edge — the grid was never centred by luck, it was centred by having a
 * sibling either side of it. */
/* Both of these are nudged up (2026-08-11).
 *
 * The middle row centres its contents, so padding-bottom moves the asset up
 * by half of it — 5rem of padding lifts the grid 40px. The bottom row is
 * align-items: flex-end, so its padding lifts the action by the full amount.
 * Padding rather than a negative margin or a transform: both of those would
 * take the element out of the box the loading bar is positioned against. */
.slot-mc {
  grid-column: 2;
  grid-row: 2;
  justify-content: center;
  align-items: center;
  padding-bottom: 5rem;
}
.slot-bc {
  grid-column: 2;
  grid-row: 3;
  justify-content: center;
  align-items: flex-end;
  padding-bottom: 1.75rem;
}
.slot-bl { grid-column: 1; grid-row: 3; justify-content: flex-start; align-items: flex-end; }
.slot-br { grid-column: 3; grid-row: 3; justify-content: flex-end;   align-items: flex-end; }

/* --- Type ------------------------------------------------------------------ */

/* The grey text is set lighter than the rest of the page (2026-08-11).
 *
 * The reference gets its airiness from PP Neue Montreal, a light-ish
 * grotesque, at #c3c3c3. GiSans Text is a sturdier face and only ships
 * Regular upward — there is no Light to ask for, so `font-weight: 300` on it
 * does nothing at all; browsers do not synthesise thinner weights, only
 * bolder ones.
 *
 * So the secondary text drops to the platform UI face, which has a real 300
 * on every OS we ship to (SF Pro Light, Segoe UI Light, Roboto Light). Two
 * sans faces on one page is normally a smell; here it is the whole point —
 * this text is meant to sit back, and the weight difference does more for
 * that than another step of grey would. The near-black text stays GiSans, so
 * everything you actually read is still the brand face.
 */
.t-muted {
  color: var(--ink-muted);
  font-family: var(--font-ui);
  font-weight: 300;
  letter-spacing: 0.01em;
}
.mark {
  display: inline-block;
  font-size: 15px;
  line-height: 1;
  color: var(--ink);
  /* The asterisk sits high on its own baseline; nudged so it optically
     centres against the two nav labels either side of it. */
  transform: translateY(2px);
}
.mark-muted {
  color: var(--ink-muted);
}

/* --- Nav / action labels ---------------------------------------------------
 * The masked roll from the reference: a fixed-height window with two copies
 * of the label stacked inside it. On hover both slide up by exactly one line,
 * so the second copy lands where the first was. The mask is what sells it —
 * without overflow: hidden this is just text sliding out of place.
 */
.roll {
  position: relative;
  display: inline-block;
  /* Same face as the caption under the grid (2026-08-11, by request). These
     five labels — About, Contact, FAQs, Gallup Q12 and the action — are the
     page's whole vocabulary, so they read as one set rather than as chrome
     in one typeface around a caption in another. */
  font-family: var(--font-ui);
  font-weight: 400;
  height: 1.6em;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  vertical-align: bottom;
}
.roll span {
  display: block;
  height: 1.6em;
  line-height: 1.6em;
  transition: transform 0.42s var(--ease);
}
.roll:hover span,
.roll:focus-visible span {
  transform: translateY(-1.6em);
}
.roll:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 3px;
}

/* Two labels a side, on one line. The gap is wide enough that they read as
   two controls rather than as a phrase. */
.nav-group {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
}
/* About and Contact are <button>s, so they need the UA's chrome stripped.
 *
 * NOT `font: inherit`, which is what this used to say: the shorthand resets
 * every font property including family, and .nav-btn comes after .roll in
 * this file — so the two buttons quietly went back to the body face while the
 * three links beside them took the new one. Only size and line-height need
 * inheriting; .roll owns the family and the weight. */
.nav-btn {
  border: 0;
  background: none;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  padding: 0;
  cursor: pointer;
}

/* --- The one committing action --------------------------------------------
 * A raised pill at every width (2026-08-11). It was an underlined link, on the
 * argument that a filled shape would be the only heavy object on a page with
 * no heavy objects — which is true, and is now the point: it is the one thing
 * on this screen you are meant to press, and it should not be competing for
 * that on equal terms with four nav labels.
 *
 * The relief is the app's own soft-UI language rather than textbook
 * neomorphism, and the difference matters. A true neomorphic pair needs the
 * plate and the ground to be the same tone, with matched light and dark
 * shadows either side; on a white page the light half of that pair is
 * invisible, and a white-on-white plate has an edge you cannot locate — which
 * is exactly what got the app's first neomorphic pass thrown out.
 *
 * So the pill borrows what does work there: a dark plate with a shallow
 * top-to-bottom gradient, a 1px inner highlight along its top edge so it
 * reads as a lit surface rather than a black rectangle, and one downward
 * shadow. It presses in on :active.
 *
 * The height comes from line-height, not vertical padding. .roll is a
 * fixed-height window with two copies of the label stacked inside it, and
 * `overflow: hidden` clips at the PADDING box, not the content box — so any
 * padding-bottom becomes a gap the second copy shows through, and the button
 * reads "Create Action Plan" twice. Growing the mask keeps one window and one
 * visible label. Horizontal padding is fine; clipping sideways costs nothing.
 */
.cta {
  position: relative;
  display: inline-block;
  height: 3.25em;
  padding: 0 1.875rem;
  border-radius: var(--r-pill);
  background-color: var(--ink);
  background-image: linear-gradient(180deg, #2b2c33 0%, #111113 62%);
  color: #fff;
  font-weight: 500;
  box-shadow:
    0 2px 4px rgb(17 17 19 / 16%),
    0 12px 26px -10px rgb(17 17 19 / 34%),
    inset 0 1px 0 rgb(255 255 255 / 14%);
  transition: box-shadow 0.32s var(--ease), transform 0.32s var(--ease);
}
.cta span {
  height: 3.25em;
  line-height: 3.25em;
}
.cta:hover span,
.cta:focus-visible span {
  transform: translateY(-3.25em);
}
.cta:hover {
  background-image: linear-gradient(180deg, #34353d 0%, #17181d 62%);
  box-shadow:
    0 3px 6px rgb(17 17 19 / 18%),
    0 18px 34px -12px rgb(17 17 19 / 40%),
    inset 0 1px 0 rgb(255 255 255 / 18%);
}
/* Pressed: the plate settles toward the page and its shadow closes up. */
.cta:active {
  transform: translateY(1px);
  box-shadow:
    0 1px 2px rgb(17 17 19 / 20%),
    0 4px 10px -6px rgb(17 17 19 / 30%),
    inset 0 1px 0 rgb(255 255 255 / 10%);
}


/* --- The letter grid -------------------------------------------------------
 * 5 columns x 4 rows of square cells. The middle row carries the name; every
 * other cell is filler that re-randomises when its row is hovered.
 *
 * Rows are real elements rather than one flat grid because the hover handler
 * works a row at a time — with a flat grid every scramble would need index
 * arithmetic to work out which cells are siblings, and the row element makes
 * that a querySelectorAll on the thing the pointer is already inside.
 */
.letter-grid {
  display: flex;
  flex-direction: column;
  gap: var(--grid-gap);
}
.lg-row {
  display: grid;
  grid-template-columns: repeat(5, var(--cell));
  gap: var(--grid-gap);
}
.lg-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--cell);
  height: var(--cell);
  user-select: none;
}
.lg-cell span {
  display: block;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 22px;
  font-weight: 300;
  line-height: 1;
  color: var(--filler);
  /* will-change is doing real work here: every cell in a row animates at
     once, and without it the browser promotes them mid-animation, which
     shows up as a one-frame jump on the first hover of each row. */
  will-change: transform, opacity;
}

/* The name. A serif at double the size, in near-black — the only two
   variables changed, which is what makes it read as the same grid rather
   than as something pasted on top of it. */
.lg-cell[data-pinned] span {
  font-family: Tobias, Georgia, "Times New Roman", serif;
  font-size: 44px;
  color: var(--name);
}

/* The grid and the line that names it, as one centred column. */
.center-stack {
  position: relative;   /* the loading bar hangs off this */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.5rem;
}
/* The caption is the one piece of grey text that is actually meant to be
   read rather than glanced past, so it does not take the muted treatment's
   full step back: bigger than the corner type ever was, and dark enough to
   sit against the name above it rather than fade off the page. */
.caption {
  margin: 0;
  font-size: 17px;
  font-weight: 400;
  color: var(--ink-caption);
  letter-spacing: 0;
  text-align: center;
}

/* --- Brand marks -----------------------------------------------------------
 * The two black SVGs in the bottom corners. Sized off their own artwork
 * rather than given a box: the wordmark is wide and short, the signature is
 * squarer, so one shared height would leave them looking mismatched.
 */
.brand-mark {
  display: block;
  height: 26px;
  width: auto;
  /* Branding, not content. At full strength two black logos are the heaviest
     things on a page built on nothing being heavy, and they pull the eye off
     the centre — which is the whole composition. */
  opacity: 0.55;
  transition: opacity 0.42s var(--ease);
}
.brand-mark:hover {
  opacity: 0.8;
}
.brand-mark-signature {
  height: 30px;
}

/* --- The cursor strip ------------------------------------------------------
 * A coloured vertical band that follows the pointer across the page. Anything
 * it passes over renders in the band's own contrasting colour.
 *
 * The idea is from specia1ne.com, where a section arrives as a narrow blue
 * column and widens to full bleed as it scrolls in, its text set light while
 * everything outside stays dark. That page is a long scroll; this one is a
 * single screen with nothing to scroll, so the band tracks the pointer
 * instead of the scroll position.
 *
 * HOW THE COLOUR SWAP WORKS, because it is not obvious.
 *
 * There are three layers stacked in the same place:
 *
 *   1. .landing-frame          the real page, dark text on white
 *   2. .cursor-strip           the blue band
 *   3. .invert-layer           a copy of the page, all text white, clipped
 *                              to exactly the band's left and right edges
 *
 * So the band paints over the real text, and the clipped copy paints the same
 * words back on top in white. Move the band and the clip moves with it.
 *
 * The obvious alternative is mix-blend-mode: difference on the band, which
 * needs no copy at all — but on a white page difference forces the band's
 * colour to be the inverse of what you want (blue text on white would demand
 * a yellow band), and there is no way to get "blue band, white text" out of
 * it. The copy is more machinery and the only way to choose both colours.
 *
 * The copy is inert: aria-hidden, no pointer events, and its ids stripped so
 * the document keeps one #letter-grid.
 */
.cursor-strip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 5;
  width: var(--strip-w);
  height: 100dvh;
  background-color: var(--strip-color);
  transform: translate3d(calc(var(--strip-x) - var(--strip-w) / 2), 0, 0) scaleX(var(--strip-scale, 1));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s var(--ease);
  will-change: transform, opacity;
}
.invert-layer {
  position: fixed;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  /* Clipped to the band. The two insets are the page either side of it, so
     only the slice under the band is ever painted. */
  clip-path: inset(
    0
    calc(100vw - var(--strip-x) - var(--strip-w) / 2)
    0
    calc(var(--strip-x) - var(--strip-w) / 2)
  );
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
/* The copy's palette.
 *
 * This was a single blanket rule setting everything to white, which is what
 * flattened the grid: outside the band the filler is a light grey against a
 * near-black MAP, and inside it every letter came out the same white, so the
 * name stopped being the thing you read. The band now carries the same three
 * steps the page does, inverted — quiet filler, brighter caption, the name at
 * full strength.
 *
 * The specific selectors have to out-rank the originals they are replacing
 * (.lg-cell span and friends), which is why they name the same elements
 * rather than leaning on a wildcard.
 */
.invert-layer,
.invert-layer * {
  color: var(--strip-ink);
  border-color: color-mix(in srgb, var(--strip-ink) 30%, transparent);
}
.invert-layer .lg-cell span {
  color: var(--strip-filler);
}
.invert-layer .lg-cell[data-pinned] span {
  color: var(--strip-ink);
}
.invert-layer .caption,
.invert-layer .t-muted {
  color: var(--strip-caption);
}
/* The two logos are black artwork; inverted they need to read as light. */
.invert-layer .brand-mark {
  filter: invert(1);
  opacity: 0.85;
}
/* The copy is a clone, so :hover never fires on it — the pointer is over the
 * original underneath. Without these the action and the nav labels sat frozen
 * whenever the band was over them, which reads as the hover being broken.
 * The script mirrors the class across; this is what it drives. */
/* A near-black pill inside a near-black band would simply vanish, so in the
   copy it flips: light plate, dark label, and the highlight moves to the
   underside where the light now comes from. */
/* The label has to be named directly, not left to inherit. The copy's blanket
   `.invert-layer *` rule paints every element white and matches the two <span>s
   inside the pill at the same specificity as anything set on their parent — so
   colouring the <a> alone left a white label on a white plate and the button
   came out blank. */
.invert-layer .cta span {
  color: var(--strip-color);
}
/* The plate inverts, the RELIEF DOES NOT (2026-08-11).
 *
 * This used to be a flat white capsule — background-image: none and a single
 * soft shadow — so the one object on the page with any depth to it went
 * completely flat every time the band passed over it, which read as the
 * button breaking rather than as it changing colour.
 *
 * The light still comes from above, so inverting the plate inverts where the
 * highlight lives: on the dark pill the lit edge is the top and the plate
 * darkens downward; on this one the plate is brightest at the top and falls
 * to a light grey, with the crisp white line still along the top edge and a
 * thin dark line underneath it to seat the shape. The drop shadow goes
 * heavier, not lighter — it is cast onto near-black now, and the 34% it had
 * was invisible against it.
 */
.invert-layer .cta {
  background-color: var(--strip-ink);
  background-image: linear-gradient(180deg, #ffffff 0%, #e4e4e9 62%);
  color: var(--strip-color);
  box-shadow:
    0 2px 5px rgb(0 0 0 / 55%),
    0 14px 28px -10px rgb(0 0 0 / 65%),
    inset 0 1px 0 rgb(255 255 255 / 95%),
    inset 0 -1px 0 rgb(0 0 0 / 14%);
}
.invert-layer .roll.is-hover span {
  transform: translateY(-1.6em);
}
/* The action's mask is taller than a nav label's, so its roll has further to
   travel — one label height, which for this element is 3.25em. */
.invert-layer .cta.is-hover span {
  transform: translateY(-3.25em);
}
body.strip-on .cursor-strip,
body.strip-on .invert-layer {
  opacity: 1;
}

/* --- The strip, opened out into a sheet ------------------------------------
 * FAQs and Gallup Q12 widen the band into a panel on the right instead of
 * navigating. The band is already a black plane pinned to the full height of
 * the window, so the only thing that has to change is how wide it is and
 * where it sits — which is the whole reason the effect and the panel are the
 * same element rather than two.
 *
 * The width and position transitions are only ever on during the open and
 * close: the rest of the time --strip-x is rewritten every frame by the
 * pointer follow, and a transition on top of that would fight the easing
 * already in the follow and lag the band behind the cursor.
 */
.cursor-strip.is-sheet {
  transition: opacity 0.35s var(--ease),
              width 0.55s var(--ease-sheet),
              transform 0.55s var(--ease-sheet);
}
body.sheet-open .cursor-strip {
  opacity: 1;
}
/* The inverted copy is meaningless once the band is a panel — it would paint
   the landing page's own words across the sheet's text. */
body.sheet-open .invert-layer {
  opacity: 0;
}

.strip-sheet {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 7;
  display: flex;
  flex-direction: column;
  width: var(--panel-w, 30rem);
  max-width: 100vw;
  height: 100dvh;
  padding: 20px 28px 28px;
  overflow-y: auto;
  color: var(--strip-ink);
  opacity: 0;
  /* Waits for the panel to arrive before fading in — text sliding in on a
     plane that is still growing under it reads as two separate things
     happening at once. */
  transition: opacity 0.3s var(--ease) 0.18s;
}
.strip-sheet[hidden] {
  display: none;
}
.strip-sheet.is-open {
  opacity: 1;
}

.sheet-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.75rem;
}
.sheet-eyebrow {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--strip-caption);
}
.sheet-close {
  border: 0;
  background: none;
  padding: 0;
  font-size: 13px;
  color: var(--strip-ink);
  cursor: pointer;
}

.sheet-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.sheet-list > li {
  border-top: 1px solid rgb(255 255 255 / 16%);
}
.sheet-list > li:last-child {
  border-bottom: 1px solid rgb(255 255 255 / 16%);
}
/* name="faqs" / name="q12" makes each list a native single-open accordion:
   opening one closes the last, which in a column this narrow is the
   difference between a list and a wall of text. */
.sheet-row {
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  padding: 0.9375rem 0;
  cursor: pointer;
  list-style: none;
}
.sheet-row::-webkit-details-marker {
  display: none;
}
.sheet-num {
  flex: 0 0 auto;
  padding-top: 3px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: rgb(255 255 255 / 45%);
}
.sheet-caret {
  position: relative;
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  margin-top: 6px;
  margin-left: auto;
  opacity: 0.55;
  transition: transform 0.28s var(--ease), opacity 0.28s var(--ease);
}
/* A plus that becomes a minus — two rules, the upright one folding away. */
.sheet-caret::before,
.sheet-caret::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background-color: var(--strip-ink);
}
.sheet-caret::before {
  width: 100%;
  height: 1px;
}
.sheet-caret::after {
  width: 1px;
  height: 100%;
  transition: transform 0.28s var(--ease);
}
.sheet-item[open] .sheet-caret {
  opacity: 0.9;
}
.sheet-item[open] .sheet-caret::after {
  transform: scaleY(0);
}
.sheet-body {
  /* Lined up under the question rather than under the number: 10px of number
     plus the 14px gap. */
  padding: 0 0 1.125rem 1.5rem;
}
.sheet-label {
  margin: 0 0 0.1875rem;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 9.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 42%);
}
.sheet-label + .sheet-a {
  margin-top: 0;
}
.sheet-a + .sheet-label {
  margin-top: 0.75rem;
}
/* The themes a manager has to plan against this cycle, marked the same way
   the full Q12 page marks them. */
.sheet-num.is-mandatory {
  color: var(--strip-ink);
  font-weight: 600;
}
.sheet-q {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 15px;
  line-height: 1.35;
  color: var(--strip-ink);
}
.sheet-a {
  margin: 0.3125rem 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--strip-caption);
}

/* No pointer, no band. A touch device has no hover to track, and a band
   parked wherever the last tap landed is just a stripe across the page. */
@media (hover: none), (pointer: coarse) {
  /* The band goes, but not when it is being used as a panel — FAQs and
     Gallup Q12 have to open on a phone too, and the strip is the panel. */
  .cursor-strip:not(.is-sheet),
  .invert-layer {
    display: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .cursor-strip,
  .invert-layer {
    transition: none;
  }
}

/* --- The loading screen ----------------------------------------------------
 * There is no overlay. The page renders as it will finally look, with its
 * chrome held back by body.is-loading while the grid's own letters roll; the
 * bar below is the only element that exists purely for loading.
 *
 * This replaces a white plate carrying a second copy of the grid. Two grids
 * meant two layouts and the word jumped between them at the handover; one
 * grid cannot.
 */
.loader-bar {
  position: absolute;
  top: calc(100% + 2.25rem);
  left: 50%;
  z-index: 40;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.875rem;
  width: min(24rem, 72vw);
  transition: opacity 0.4s var(--ease);
}
.loader-bar.is-done {
  opacity: 0;
  pointer-events: none;
}
.loader-pct {
  flex: 0 0 auto;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.loader-rule {
  position: relative;
  flex: 1;
  height: 1px;
  background-color: #e4e4e8;
}
.loader-rule-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background-color: var(--ink);
}

/* --- Panels (About / Contact) ----------------------------------------------
 * The two things the old landing page could do that this one still has to.
 * Plain white sheets over the page, no scrim tint heavy enough to make the
 * page behind them feel switched off.
 */
.panel {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background-color: rgb(255 255 255 / 92%);
  backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.32s var(--ease), visibility 0.32s;
}
.panel[data-open] {
  opacity: 1;
  visibility: visible;
}
.panel-inner {
  width: 100%;
  max-width: 30rem;
  /* Ten HRBPs plus a heading is taller than a short laptop window, and the
     panel is fixed to the viewport — without this the last rows are simply
     unreachable. */
  max-height: calc(100dvh - 8rem);
  overflow-y: auto;
  transform: translateY(6px);
  transition: transform 0.42s var(--ease);
}
.panel[data-open] .panel-inner {
  transform: translateY(0);
}
.panel h2 {
  margin: 0 0 0.75rem;
  font-family: Tobias, Georgia, "Times New Roman", serif;
  font-size: 28px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--name);
}
.panel p {
  margin: 0 0 0.75rem;
  max-width: 42ch;
  color: var(--ink);
}
/* The one sentence the panel is built around — set at the serif's size but
   in the sans, so it leads without competing with the heading above it. */
.panel-lead {
  font-size: 17px;
  line-height: 1.45;
}
.panel-sub {
  margin: 1.5rem 0 0.5rem;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.panel-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid #ededed;
}
.panel-list li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid #ededed;
}
.panel-list .zone {
  color: var(--ink-muted);
}
.panel-close {
  position: fixed;
  top: 20px;
  right: 24px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}

/* --- Entrance --------------------------------------------------------------
 * The page's chrome — the nav, the action, the two marks — is held at zero
 * while body.is-loading is set, and fades in on its own stagger when the
 * loading run finishes. The caption and the grid are deliberately NOT in this
 * set: they are what the loading state shows.
 *
 * A transition driven by the class, not a keyframe animation with a delay.
 * An animation would play out on its own schedule regardless of whether
 * loading had finished, which is the thing this has to wait for.
 *
 * The animation below it is the failsafe: if the script never runs, nothing
 * ever removes .is-loading, and without this the page would sit with no nav
 * and no way in. At 6s it reveals everything regardless.
 */
.landing-frame [data-enter] {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  transition-delay: var(--enter-delay, 0s);
}
body.is-loading .landing-frame [data-enter] {
  opacity: 0;
  transform: translateY(6px);
  animation: enter-failsafe 0.01s linear 6s forwards;
}
@keyframes enter-failsafe {
  to {
    opacity: 1;
    transform: none;
  }
}

/* --- Reduced motion --------------------------------------------------------
 * The letter scramble is the page's whole idea, so it is not removed here —
 * it just stops animating. The JS reads this same query and swaps letters
 * instantly instead of cross-fading them.
 */
@media (prefers-reduced-motion: reduce) {
  .landing-frame [data-enter] {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .roll span,
  .cta,
  .panel,
  .panel-inner,
  .lg-cell span {
    transition: none;
  }
  /* The strip still marks the row, it just stops sweeping open. */
  .lg-row::before,
  .lg-row::after {
    transition: none;
  }
}

/* --- Narrow screens --------------------------------------------------------
 * The grid is the only thing that cannot shrink gracefully: five 76px cells
 * plus gaps need 428px, and a phone has 390. Rather than scaling the type
 * down until it is unreadable, the cells shrink and the mid-row labels that
 * flank the grid drop out — they are the two pieces of the composition that
 * have nowhere to go once the grid reaches the screen edges.
 */
@media (max-width: 640px) {
  :root {
    --cell: 58px;
    --grid-gap: 8px;
  }
  .landing-frame {
    padding: 16px;
  }
  .lg-cell span {
    font-size: 17px;
  }
  .lg-cell[data-pinned] span {
    font-size: 34px;
  }
  /* The three-column frame does not survive 390px: the flanking labels have
   * nowhere to sit, and four-line corner blocks set a minimum width for the
   * outer columns that pushes the grid off the screen entirely — which is
   * exactly what the first attempt did.
   *
   * The reference solves it by subtraction, and so does this: the flanking
   * labels go, both corner stacks go, and one centred line under the grid
   * says what they were saying. What is left is the nav row, the grid, the
   * line, the sign-in and two short words in the bottom corners. */
  /* The frame's columns change shape here, and this is the fix that actually
   * mattered when the corners still had text in them.
   *
   * At 1fr auto 1fr the middle column sizes to the grid (322px) while the two
   * outer columns still have to hold the nav labels — unshrinkable text on
   * both sides. Add the gaps and the page padding and the frame demands more
   * than a 390px screen has, so it overflowed and the grid's first column
   * went off the left edge.
   *
   * auto 1fr auto inverts it: the nav takes exactly what it needs, the middle
   * column takes the rest, and the grid spans all three and centres itself in
   * the full width instead of inside one squeezed column. */
  .landing-frame {
    grid-template-columns: auto 1fr auto;
  }
  /* The grid spans the full width, and the action takes a row of its own
   * above the two marks.
   *
   * Sharing a row with them does not work here: the wordmark is about twice
   * the width of the signature, so the 1fr column between them is not
   * centred on the page and neither is anything in it — "Create Action Plan"
   * came out visibly right of centre, on the one page where the centre line
   * is the composition. Its own row costs a few pixels of height and buys
   * back the symmetry. */
  .slot-mc {
    grid-column: 1 / -1;
  }
  .slot-bc {
    grid-column: 1 / -1;
    grid-row: 3;
    margin-bottom: 1.75rem;
  }
  .slot-bl { grid-row: 4; }
  .slot-br { grid-row: 4; }
  .brand-mark {
    height: 18px;
  }
  .brand-mark-signature {
    height: 21px;
  }
  .center-stack {
    gap: 2rem;
  }
  .caption {
    font-size: 14px;
  }

  /* Only the size changes here — the pill itself is the base treatment now. */
  .cta {
    padding: 0 1.5rem;
  }
  .nav-group {
    gap: 0.875rem;
  }
  :root {
    --strip-w: 110px;
  }
  body.landing {
    font-size: 13px;
  }
}

/* Below 380px even 58px cells overflow, so the last thing to give is the
   grid's outer column — four columns still spells the name with one filler
   either side. Handled in JS (it owns the letters); this only sizes it. */
@media (max-width: 380px) {
  :root {
    --cell: 52px;
    --grid-gap: 6px;
  }
}
