/* ==========================================================================
   SURFACE — material and tonal rhythm
   ==========================================================================
   Two problems this fixes.

   1. The page ran on one flat light paper from top to bottom, so every
      section carried the same weight and the eye had nothing to travel
      toward. The finance-stack section is now full-bleed dark: the page
      breathes in, holds, and comes back out.

   2. Flat colour has no material. Real paper has tooth. A fine grain sits
      over every surface — heavy enough to feel, light enough that you would
      not name it if asked.
   ========================================================================== */

:root{
  --night:#141319;          /* the dark ground: ink, one step open */
  --night-soft:#1D1C24;     /* raised surface on night */
  --night-line:rgba(255,255,255,.10);
  --night-text:#EDEBF2;
  --night-muted:#B3B0C2;   /* 6.4:1 on the brightest raised night surface */
  --night-quiet:#9B98A9;   /* 4.8:1 on the same */
  /* No single amber clears 4.5:1 on both paper and night, so the signal
     carries two values. #8A5A1E is 3.13:1 on night; this is 5.6:1. */
  --amber-night:#C57D20;
}

/* --------------------------------------------------------------------------
   Grain. One tiled SVG turbulence, composited over the ground rather than
   applied per element, so it never multiplies with itself at section seams.
   -------------------------------------------------------------------------- */
body::before{
  content:"";
  position:fixed;
  inset:0;
  z-index:9999;
  pointer-events:none;
  opacity:.30;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  background-size:180px 180px;
}
@media (prefers-reduced-motion:no-preference){
  /* Grain that never moves reads as a dirty screen; a slow drift reads as
     paper. Two-pixel steps, eight seconds — below conscious notice. */
  body::before{animation:grain-drift 8s steps(6) infinite}
  @keyframes grain-drift{
    0%,100%{transform:translate(0,0)}
    20%{transform:translate(-2px,1px)}
    40%{transform:translate(1px,-2px)}
    60%{transform:translate(-1px,-1px)}
    80%{transform:translate(2px,1px)}
  }
}

/* ==========================================================================
   The finance stack — the sentence, not the diagram
   ==========================================================================
   Two things were wrong and they were connected.

   The ground was lilac. It was introduced to give the section its own
   identity after it stopped being dark, but a violet field under a page of
   warm neutrals is not a quiet differentiator — it is the loudest thing on
   the page, and it made the one section that is about OTHER people's systems
   look like the most branded.

   And the design was a hub-and-spoke diagram that did not diagram anything:
   a large hollow box with four corners of text and a card floating in the
   middle, then a second stacked block underneath repeating the ledger choice.
   The corners carried no relationship to each other, the box was mostly
   empty, and the whole thing took two full screens to say one sentence.

   The sentence is: activity happens in your systems, Zenday prepares it, the
   approved work lands in a ledger. So the section is laid out as that
   sentence, left to right, with a hairline running through the middle that
   the work travels along. One row, one idea, half the height, and the ground
   goes back to the page's own neutral.
   ========================================================================== */

.zen-integrations{
  position:relative;
  isolation:isolate;
  border-top:0;
  background:var(--canvas);
}

/* --------------------------------------------------------------------------
   The rolodex — four categories, every cell a real mark
   --------------------------------------------------------------------------
   The version before this mixed registers and it showed: seven cells carried
   a brand mark and five carried the brand's name set in this page's own
   typeface, because two public collections between them did not have Ramp,
   BILL, Rippling, Deel or Mercury. A logo wall where some entries are logos
   and some are captions does not read as a wall.

   So the roster is chosen from what real marks exist for, rather than the
   marks being chosen to fit a roster. Twenty-seven of them across the four
   categories a finance team actually thinks in, every one a real logo, all
   monochrome, all self-hosted — no cell is a caption.

   Each column turns at its own rate (34s / 43s / 38s / 47s, all prime-ish
   against each other) so the four never lock into one moving block, and each
   is masked top and bottom so marks arrive and leave rather than appearing
   at a hard edge.
   -------------------------------------------------------------------------- */
.rolo{
  margin-top:clamp(40px,4.6vw,58px);
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:0 clamp(20px,2.6vw,44px);
}

.rolo-col{display:grid;align-content:start}

.rolo-cat{
  margin:0 0 22px;
  display:grid;
  gap:5px;
  padding-bottom:16px;
  border-bottom:1px solid var(--line-soft);
}
.rolo-cat span{
  color:var(--ink);
  text-transform:uppercase;
  letter-spacing:.115em;
  font-size:11.5px;
  font-weight:700;
}
.rolo-cat small{color:var(--quiet);font-size:11.5px;line-height:1.45}

/* The window each column turns inside. The mask IS the device — without it
   this is a box with its contents cut off at both ends. */
.rolo-window{
  position:relative;
  height:300px;
  overflow:hidden;
  /* The mask makes a stacking context; anything blending inside it needs a
     backdrop of its own, so paint one rather than inherit nothing. */
  background:var(--canvas);
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 14%,#000 86%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 14%,#000 86%,transparent 100%);
}

.rolo-track{
  display:grid;
  grid-auto-rows:48px;
  gap:44px;
  /* The trailing gap the grid does not draw. Without it a track of n rows is
     n rows + (n-1) gaps, so translating -50% moves less than the pattern's
     own period and the loop jumps a little every cycle — small enough to read
     as a glitch rather than a bug, which is worse. With it, -50% lands
     exactly on the period whatever n is, and the columns can hold different
     numbers of marks. */
  padding-bottom:44px;
  will-change:transform;
}
html[data-motion="ready"] .rolo-track{
  animation:rolo-turn var(--dur,38s) linear infinite;
}
@keyframes rolo-turn{
  from{transform:translate3d(0,0,0)}
  to  {transform:translate3d(0,-50%,0)}
}

/* Stop it when someone is trying to look at one. */
.rolo-window:hover .rolo-track,
.rolo-window:focus-within .rolo-track{animation-play-state:paused}

.rolo-cell{display:flex;align-items:center;gap:14px;height:48px}

/* --------------------------------------------------------------------------
   The marks — app tiles, and the brand name beside each
   --------------------------------------------------------------------------
   The roster changed before the styling did, and the roster was the actual
   defect: Spend & AP held Visa, Mastercard and American Express, which are
   card NETWORKS, not systems an accounting product integrates with. They were
   there because I had their logos, which is the wrong reason to put a brand on
   a page. Researched properly, that category is Ramp, BILL, Brex, Expensify
   and Coupa.

   Getting the right brands meant giving up wordmarks. Nine collections were
   checked — Simple Icons, VectorLogoZone, gilbarbara, svgl, geticon, Composio,
   Nango, Expensify's own app, and a bank-logo set — roughly 20,000 files. Not
   one publishes a wordmark for Ramp, BILL, Mercury, Deel, Rippling or Coupa.
   Every source has them as square app tiles, because that is what integration
   platforms need. Their wordmarks exist only in the companies' own press kits,
   which this sandbox's egress policy blocks.

   So: correct brands as tiles, with the brand name set beside every one. Each
   cell carries both, so nothing is odd one out — which was the real complaint
   about the mixed set, not the tile shape itself. The tile gets a hairline and
   a radius so the ones with white backgrounds sit on the ground the same way
   the coloured ones do.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Washed by default, one lit at a time
   --------------------------------------------------------------------------
   Twenty-two brand palettes at full strength would be the loudest thing on a
   page built from one indigo and a warm grey. So every tile is desaturated
   and lifted toward the paper — grayscale for the colour, and a little
   contrast off with brightness up, which is what turns a flat grey tile into
   something that reads as washed rather than switched off.

   Then one tile per column carries its real colour at any moment, and which
   one moves. That is the whole device: the eye is drawn to a different brand
   every couple of seconds without the section ever being busy, and the marks
   are still legible as themselves when they light.
   -------------------------------------------------------------------------- */
.rolo-mark{
  width:40px;
  height:40px;
  flex:none;
  object-fit:contain;
  border-radius:9px;
  box-shadow:inset 0 0 0 1px rgba(23,22,28,.07);
  background:var(--paper);
  filter:grayscale(1) contrast(.86) brightness(1.08);
  opacity:var(--rest,.72);
  transition:filter .55s var(--ease),opacity .55s var(--ease);
}
/* --------------------------------------------------------------------------
   Levelling the wash
   --------------------------------------------------------------------------
   Twenty-two marks from twenty-two brand books do not weigh the same. Half are
   filled app tiles — a solid square with a white glyph knocked out of it — and
   half are wordmarks drawn as thin ink on nothing. Desaturating them does not
   make them one material: measured on the section ground, Rippling's tile rested
   FIFTEEN TIMES heavier than Capital One's, so the grid read as a row of dark
   blocks with ghosts between them rather than one quiet set.

   So the resting opacity is set per mark, to the value that lands each one on
   the same measured ink weight. The heavy tiles come down; the faint wordmarks
   are already under it and stay at full. That closes the range to about 3x.
   Lighting a brand still returns it to filter:none, opacity:1 — its own colour,
   its own weight.
   -------------------------------------------------------------------------- */
.rolo-mark[data-mark="rippling"]{--rest:0.22}
.rolo-mark[data-mark="square"]{--rest:0.26}
.rolo-mark[data-mark="citibank"]{--rest:0.27}
.rolo-mark[data-mark="stripe"]{--rest:0.30}
.rolo-mark[data-mark="chase"]{--rest:0.31}
.rolo-mark[data-mark="hubspot"]{--rest:0.32}
.rolo-mark[data-mark="gusto"]{--rest:0.38}
.rolo-mark[data-mark="deel"]{--rest:0.46}
.rolo-mark[data-mark="paychex"]{--rest:0.59}
.rolo-mark[data-mark="coupa"]{--rest:0.65}
.rolo-mark[data-mark="salesforce"]{--rest:0.66}
.rolo-mark[data-mark="workday"]{--rest:0.67}
.rolo-mark[data-mark="brex"]{--rest:0.67}
.rolo-mark[data-mark="shopify"]{--rest:0.77}
.rolo-mark[data-mark="paypal"]{--rest:0.77}
.rolo-mark[data-mark="ramp"]{--rest:1.00}
.rolo-mark[data-mark="bill"]{--rest:1.00}
.rolo-mark[data-mark="bankofamerica"]{--rest:1.00}
.rolo-mark[data-mark="usbank"]{--rest:1.00}
.rolo-mark[data-mark="capitalone"]{--rest:1.00}

.rolo-cell.is-lit .rolo-mark,
.rolo-cell:hover .rolo-mark{
  filter:none;
  opacity:1;
}
.rolo-cell.is-lit .rolo-name{color:var(--ink)}

.rolo-name{
  color:var(--muted);
  font-size:15.5px;
  font-weight:620;
  letter-spacing:-.02em;
  white-space:nowrap;
  transition:color .3s var(--ease);
}
.rolo-cell:hover .rolo-name{color:var(--indigo)}

/* --------------------------------------------------------------------------
   No motion: each column becomes a list
   --------------------------------------------------------------------------
   Not merely paused — paused mid-travel leaves the first and last marks
   clipped against the mask, which is a worse still image than the one it
   replaces. The window and mask come off, the track goes back to a static
   list, and the duplicate set that exists only to close the loop is hidden.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .rolo-cell.is-lit .rolo-mark{filter:grayscale(1) contrast(.86) brightness(1.08);opacity:var(--rest,.72)}
  .rolo-cell.is-lit .rolo-name{color:var(--muted)}
  .rolo-window{height:auto;-webkit-mask-image:none;mask-image:none}
  .rolo-track{padding-bottom:0;grid-auto-rows:auto;gap:26px}
  html[data-motion="ready"] .rolo-track{animation:none;transform:none}
  .rolo-cell[aria-hidden="true"]{display:none}
}
html:not([data-motion="ready"]) .rolo-window{height:auto;-webkit-mask-image:none;mask-image:none}
html:not([data-motion="ready"]) .rolo-track{padding-bottom:0;grid-auto-rows:auto;gap:26px}
html:not([data-motion="ready"]) .rolo-cell[aria-hidden="true"]{display:none}

@media (max-width:980px){
  .rolo{grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(30px,4vw,44px) clamp(24px,4vw,40px)}
}
@media (max-width:560px){
  .rolo{grid-template-columns:minmax(0,1fr);gap:30px 0}
  .rolo-window{height:246px}
}

/* --------------------------------------------------------------------------
   Where it writes to — the counterweight, one line
   -------------------------------------------------------------------------- */
.reg-out{
  margin-top:clamp(34px,3.6vw,46px);
  padding-top:26px;
  border-top:1px solid var(--line);
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  gap:16px clamp(24px,3vw,52px);
  align-items:center;
}
.reg-out-label{
  margin:0;
  color:var(--ink);
  text-transform:uppercase;
  letter-spacing:.115em;
  font-size:11.5px;
  font-weight:700;
}
.reg-out-names{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:12px clamp(22px,2.6vw,38px);
}
.reg-out-names b{
  color:var(--ink);
  font-size:17px;
  font-weight:620;
  letter-spacing:-.028em;
}
.reg-out-names .is-own{
  display:inline-flex;
  align-items:center;
  gap:9px;
  color:var(--indigo);
}
.reg-out-names .is-own .brand-mark{width:19px;height:19px}

.stack-more{
  display:inline-flex;
  align-items:center;
  gap:7px;
  color:var(--indigo);
  font-size:12.5px;
  font-weight:640;
  white-space:nowrap;
}
.stack-more:hover{color:var(--indigo-deep)}



/* --------------------------------------------------------------------------
   Narrow
   -------------------------------------------------------------------------- */
@media (max-width:980px){
  .reg{grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(28px,4vw,44px) clamp(24px,4vw,44px)}
  .stack-logo{height:30px}
}
@media (max-width:620px){
  .reg{grid-template-columns:minmax(0,1fr);gap:30px 0}
  .reg-cell{min-height:70px}
  .stack-logo{height:27px}
  .reg-out{grid-template-columns:minmax(0,1fr);gap:14px}
  .stack-more{justify-self:start}
}
