/* ============================================================================
   Floom — Threadline
   ----------------------------------------------------------------------------
   The design language, laid over the site rather than replacing it. The hero
   keeps its ramp, its photograph and its scroll behaviour; everything here is
   the thread system arriving around them.

   The primitive is a line in three strengths, taken from the three strands
   already in the logo and at the logo's own opacities:

       25%  loose   an unread input — faint, and the only thing that wobbles
       50%  woven   Floom working — three strands braided, the ONLY way AI is
                    ever drawn here. No sparkle, no orb, no robot.
      100%  ruled   the saved record — flat, full strength, ending in a cell

   A thread bends only through the logo's S-step: flat, turn, flat. It ends in
   a square cell, the shape of a spreadsheet cell, because every thread ends in
   the record. A dashed thread is what has not happened yet: a forecast.
   Nothing on the site is marked "Preview" — no chip, no flag, no dashed
   stand-in for one.

   Orange is the thread and almost nothing else. Where a control is already
   orange — the solid button is — the thread takes the foreground colour
   instead, because an orange thread on an orange ground says nothing.
   ========================================================================== */

:root{
  --th:        var(--ap-orange);
  --th-ink:    var(--ap-orange);     /* overridden on orange grounds */
  --th-w:      1.5px;                /* loose and woven */
  --th-w-ruled:1.75px;               /* the record */
  --th-ease:   cubic-bezier(.2,.7,.2,1);
  --th-cell:   8px;
  /* The ledger: ink at 7.5%, one line every 32px. The ink is the site's own,
     so this introduces no colour the design-system check has to learn. */
  --th-rule:   color-mix(in srgb, var(--ap-ink) 7.5%, transparent);
}

/* ── the cell ─────────────────────────────────────────────────────────────*/
.th-cell{
  display: inline-block; flex: none;
  width: var(--th-cell); height: var(--th-cell);
  background: var(--th-ink);
}
.th-cell.is-open{
  background: transparent;
  box-shadow: inset 0 0 0 1.25px var(--th-ink);
}

/* ── the arrow: a thread that ends in a cell ──────────────────────────────
   On hover the thread grows and the cell fills — the action lands. This is
   the whole of the button's motion; the button itself does not move. */
/* The parts are .th-ln and .th-cl, not the design document's .ln and .cl:
   .cl is already this site's clients band, and a bare .cl here inherited its
   140px of top padding and drew the cell as a column. */
.th-arrow{ display: inline-flex; align-items: center; flex: none; }
.th-arrow > i{ display: block; flex: none; }
.th-arrow .th-ln{
  width: 16px; height: var(--th-w-ruled);
  background: var(--th-ink);
  transition: width .24s var(--th-ease);
}
.th-arrow .th-cl{
  width: 7px; height: 7px;
  box-shadow: inset 0 0 0 1.5px var(--th-ink);
  transition: background .24s var(--th-ease);
}
:is(a,button,.th-card):is(:hover,:focus-visible) .th-arrow .th-ln{ width: 24px; }
:is(a,button,.th-card):is(:hover,:focus-visible) .th-arrow .th-cl{ background: var(--th-ink); }

/* ── the text link: words, then the thread ────────────────────────────────
   The way on from a section. It lives here, beside the arrow it ends in,
   because every page loads this file and not every page loads the home
   page's floom-story.css, where it started. */
.st-links{ display: flex; flex-wrap: wrap; gap: 12px 28px; }
.st-link{
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--font);
  font-size: 15.79px; font-weight: 600; line-height: 1;
  color: var(--black);
  transition: color .24s var(--th-ease, cubic-bezier(.2,.7,.2,1));
}
.st-link:is(:hover, :focus-visible){ color: var(--ap-orange); }

/* The site's buttons carry an arrow glyph in their markup, twice over for the
   label swap. Rather than edit every one of them on every page, the glyph
   stands down and the thread is drawn by the button itself — ::before is the
   thread, ::after the cell, both ordered past the label. */
.ap-btn svg{ display: none; }
.ap-btn{ gap: 8px; }
.ap-btn::before,
.ap-btn::after{ content: ""; display: block; flex: none; }
.ap-btn::before{
  order: 1;
  width: 16px; height: var(--th-w-ruled);
  background: var(--th-ink);
}
.ap-btn::after{
  order: 2;
  width: 7px; height: 7px;
  box-shadow: inset 0 0 0 1.5px var(--th-ink);
  /* The button's own 10px gap would leave the thread stopping short of the
     cell; the thread has to end IN it. */
  margin-left: -8px;
}
/* The thread and its cell hold still on hover (2026-10-16, at the user's
   request): growing the thread made the whole button wider, and the label's
   roll is the only motion a button has. */
/* The solid button is already the thread's colour, so its thread is drawn in
   the foreground instead — the rule is that orange marks what Floom touched,
   and an orange mark on orange marks nothing. */
.ap-btn-solid{ --th-ink: currentColor; }

/* ── navigation: the S-step underline ─────────────────────────────────────
   No pill, no background. The current page and the hovered link get the
   logo's own step, drawn left to right. The bar is a mask so the shape is the
   thread's rather than a rectangle's, and the stroke's horizontal runs keep
   their weight at any link width — only the step itself skews, by a few
   tenths of a pixel over a nav link. */
.nav-links a::after,
.nav-links .nv-trigger::after{
  content: "";
  position: absolute; left: 0; right: 0; bottom: -1px;
  height: 7px;
  border-radius: 0;
  background: var(--th);
  transform: none;
  -webkit-mask: var(--th-step) center / 100% 100% no-repeat;
          mask: var(--th-step) center / 100% 100% no-repeat;
  clip-path: inset(0 100% 0 0);
  transition: clip-path .32s var(--th-ease);
}
.nav-links a:is(:hover,:focus-visible)::after,
.nav-links .nv-trigger:is(:hover,:focus-visible)::after,
.nav-links a[aria-current="page"]::after{ clip-path: inset(0 0 0 0); }
.nav-links .nv-trigger{ position: relative; }

:root{
  --th-step: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 7' preserveAspectRatio='none'%3E%3Cpath d='M1 5.8H38C50 5.8 50 1.2 62 1.2H99' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* The status badge that used to live here — a dashed outline reading
   PREVIEW, BETA or COMING SOON — is gone, and so is the one place that used
   it. Fund Modeling's weave is dashed after TODAY because that part is a
   forecast, not because the product is marked as anything. */
/* ── the braid: the only way the site draws AI ────────────────────────────
   Three strands crossing, moving left to right while Floom is reading. It
   replaces the spinner outright: a spinner says something is happening
   somewhere, the braid says what is happening. */
.th-braid{
  display: block;
  height: 24px;
  /* Painted, not drawn: the three strands are masks so their colour is the
     thread token rather than a hex baked into a data URI, which is a colour
     the design-system check cannot see past. Each layer carries its own
     strength in the mask's own alpha — 100, 50 and 25, the logo's three. */
  background: var(--th);
  -webkit-mask-image: var(--th-braid-1), var(--th-braid-2), var(--th-braid-3);
          mask-image: var(--th-braid-1), var(--th-braid-2), var(--th-braid-3);
  -webkit-mask-repeat: repeat-x, repeat-x, repeat-x;
          mask-repeat: repeat-x, repeat-x, repeat-x;
  -webkit-mask-size: 48px 100%, 48px 100%, 48px 100%;
          mask-size: 48px 100%, 48px 100%, 48px 100%;
  -webkit-mask-position: 0 0, -16px 0, -32px 0;
          mask-position: 0 0, -16px 0, -32px 0;
}
.th-braid.is-running{ animation: th-braid 1.4s linear infinite; }
@keyframes th-braid{
  to{
    -webkit-mask-position: 48px 0, 32px 0, 16px 0;
            mask-position: 48px 0, 32px 0, 16px 0;
  }
}
:root{
  --th-braid-1: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 24'%3E%3Cpath d='M0 12Q6 5 12 12T24 12T36 12T48 12' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E");
  --th-braid-2: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 24'%3E%3Cpath d='M0 12Q6 5 12 12T24 12T36 12T48 12' fill='none' stroke='%23000' stroke-opacity='.5' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E");
  --th-braid-3: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 24'%3E%3Cpath d='M0 12Q6 5 12 12T24 12T36 12T48 12' fill='none' stroke='%23000' stroke-opacity='.25' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* ── ledger paper ─────────────────────────────────────────────────────────*/
.th-ruled{
  background-image: repeating-linear-gradient(
    to bottom, transparent 0 31px, var(--th-rule) 31px 32px);
}

/* ── the bottom line ──────────────────────────────────────────────────────
   The accountant's double underline, and the cell that every thread ends in
   sitting on its right. A story closes here. */
.th-bottomline{
  position: relative;
  height: 5px;
  border-top: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
}
.th-bottomline::after{
  content: "";
  position: absolute; right: 0; top: -4px;
  width: 10px; height: 10px;
  background: var(--th);
}

/* ── the pull: a card's bottom edge ───────────────────────────────────────*/
.th-pull{
  position: absolute; left: -1px; right: -1px; bottom: -1px;
  height: 2px;
  background: var(--th);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--th-ease);
}
:is(a,.th-card,li,article):is(:hover,:focus-visible) > .th-pull{ transform: scaleX(1); }

/* ── drawing, not fading ──────────────────────────────────────────────────
   Threads appear by drawing along themselves. One mover at a time, always
   left to right, the same way loose turns into ruled. */
.th-draw{ stroke-dasharray: 1000; stroke-dashoffset: 1000; }
.th-draw.is-in{ animation: th-draw .62s var(--th-ease) forwards; }
@keyframes th-draw{ to{ stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce){
  .th-braid.is-running{ animation: none; }
  .th-draw{ stroke-dasharray: none; stroke-dashoffset: 0; }
  .th-arrow .ln, .th-arrow .cl,
  .ap-btn::before, .ap-btn::after,
  .nav-links a::after, .th-pull{ transition-duration: 0s; }
}

/* ── the eyebrow's lead-in ────────────────────────────────────────────────
   The hero's eyebrow carried a square before its words; it carries the same
   short S-step the thread bends through, so the shape that runs under a nav
   link and along a button also introduces the page. (The clients band had one
   too, until the band became a single line between two rules.) One shape, every scale.

   Drawn as a mask rather than an SVG in the markup so the colour stays the
   token and the two existing elements need no new HTML. */
:root{
  --th-lead: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 10'%3E%3Cpath d='M1 8.5H9C14 8.5 14 1.5 19 1.5H27' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}
/* .ap-hero-eyebrow's own rule sets the mark at .72em and outranks a bare
   class, so the hero's is named through its parent to match it. */
.ap-hero-eyebrow .ap-eyebrow-dot,
.ap-eyebrow-dot{
  width: 28px; height: 10px;
  flex: none;
  border: 0;
  border-radius: 0;
  background: var(--th-ink);
  -webkit-mask: var(--th-lead) center / 100% 100% no-repeat;
          mask: var(--th-lead) center / 100% 100% no-repeat;
}
/* The hero's chip sits on the ramp, where the thread reads as itself. */
.ap-hero-eyebrow{ --th-ink: var(--ap-orange); }

/* ── the menu control: the logo's three strands ───────────────────────────
   The bar's three bars were three bars. They are the same three strands the
   logo is built from now, carrying the logo's own opacities and reading in
   the language's order — loose at the top, woven, ruled at the foot — so the
   control that opens the menu is made of the same thing as everything the
   menu leads to. Stroke drops from 2 to the ruled weight.

   Open, it still crosses into an X, because that is the close affordance
   people already know; both strokes go to full strength there, since a half
   strength X would read as a disabled one rather than as a woven one. */
.nav-toggle svg path{ stroke-width: 1.75; }
.nav-toggle svg path:nth-of-type(1){ opacity: .25; }
.nav-toggle svg path:nth-of-type(2){ opacity: .5; }
.nav-toggle svg path:nth-of-type(3){ opacity: 1; }
.nav.menu-open .nav-toggle svg path,
.nav.links-open .nav-toggle svg path{ opacity: 1; }
.nav.menu-open .nav-toggle svg path:nth-of-type(2),
.nav.links-open .nav-toggle svg path:nth-of-type(2){ opacity: 0; }

/* ── breadcrumbs ──────────────────────────────────────────────────────────
   The chevrons between the crumbs went with the dropdown caret. A short
   ruled thread separates them instead — the crumbs are a path through the
   site, and a path is the one thing this language already draws. */
.fp-crumbs > * + *{ display: inline-flex; align-items: center; }
.fp-crumbs > * + *::before{
  content: "";
  display: inline-block;
  width: 12px; height: var(--th-w-ruled);
  margin: 0 8px;
  background: var(--th);
  flex: none;
}

/* ── the features sheet ───────────────────────────────────────────────────
   The one mark in the sheet was a → character, shown only on the item that is
   current and hidden on the rest. It keeps that behaviour — six orange marks
   in one sheet would be a row of them rather than a pointer — and becomes the
   thread ending in a filled cell, which is what the rest of the site now says
   for "this is the one". The opacity and the slide it already had still run;
   only the glyph changed.

   A mask rather than a character, so the colour is the token. The stroke
   inside it is black because a mask reads alpha and the paint comes from the
   background. */
:root{
  --th-tip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 8'%3E%3Cpath d='M0 4H16' fill='none' stroke='%23000' stroke-width='1.75'/%3E%3Crect x='18' y='0' width='8' height='8' fill='%23000'/%3E%3C/svg%3E");
}
.mega-item .t::after{
  content: "";
  display: inline-block;
  width: 26px; height: 8px;
  margin-left: 8px;
  vertical-align: middle;
  background: var(--th);
  -webkit-mask: var(--th-tip) center / 100% 100% no-repeat;
          mask: var(--th-tip) center / 100% 100% no-repeat;
}

/* ── what the screen is showing ───────────────────────────────────────────
   A glass bar over the desk, carrying the four things the monitor can be
   asked about. It is not in the hero at rest: the hero has one thing to say
   at a time, so the bar arrives as the copy above it recedes, rising into
   place the way a toast does rather than fading on the spot.

   It sits on the hero, not in the monitor. The monitor is z-index 1, the
   photograph of the two people is 2, and the monitor carries a parallax
   transform — so it is its own stacking context and nothing inside it can be
   brought in front of them. A sibling at 3 can. */
.ap-tabs{
  position: absolute;
  left: 50%;
  /* Under the screen's lower edge, across the monitor's stand and clear of
     the keyboard and the hands on it. The stand runs from 16% to 24% of the
     photograph's width above the hero's foot (see "the monitor" in
     floom-apple.css), and the monitor has risen a little by the time the bar
     arrives, so 17.5% sits it on the stand. Stated against --ap-ppl, so it
     keeps its place against the photograph rather than against the copy. */
  bottom: round(calc(var(--ap-ppl, 100vw) * .175), 8px);
  z-index: 3;
  display: flex;
  gap: 8px;
  padding: 8px;
  border-radius: 20px;
  background: rgba(24, 24, 24, .38);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
          backdrop-filter: blur(20px) saturate(140%);
  box-shadow: inset 0 0 0 1px rgba(250, 246, 241, .16);
  /* The toast: up and in, held off the page until the copy has gone. */
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 22px);
  transition: opacity .3s ease-out,
              transform .62s var(--ap-swipe-ease, cubic-bezier(.2, 1.2, .35, 1)),
              visibility 0s linear .62s;
}
.ap-tabs.is-in{
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s, 0s, 0s;
}
.ap-tab{
  appearance: none;
  border: 0;
  cursor: pointer;
  padding: 12px 24px;
  border-radius: 12px;
  background: transparent;
  font-family: var(--font);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  color: rgba(250, 246, 241, .78);
  transition: background .2s ease, color .2s ease;
}
.ap-tab:hover{ color: #FAF6F1; background: rgba(250, 246, 241, .10); }
.ap-tab[aria-selected="true"]{
  background: transparent;              /* the pill under it is the fill now */
  color: var(--ap-ink);
  font-weight: 600;
}

/* ── the pill that travels ────────────────────────────────────────────────
   The selected tab used to take the fill itself, so switching was a swap:
   one went white as another went dark, with nothing in between. The fill is
   its own element now and it slides, on the same damped spring the nav's
   links ride in on — it runs past its mark and settles back rather than
   easing to a stop.

   The liquid part is the stretch. It takes a scaleX for the length of the
   trip, set from the distance, so it draws out as it leaves and gathers back
   as it lands; the radius is in pixels and scales with it, which is what
   makes the ends read as a skin rather than a box. Width animates on its own
   slightly faster clock, so a short label arriving at a long one fills out
   just after the body gets there. */
.ap-tab-ind{
  position: absolute;
  top: 8px;
  left: 0;
  height: calc(100% - 20px);
  width: var(--w, 0px);
  pointer-events: none;
  z-index: 0;
  /* The body travels: translate and width only, on the spring. */
  transform: translateX(var(--x, 0px));
  transition:
    transform  .62s var(--ap-swipe-ease, cubic-bezier(.2, 1.2, .35, 1)),
    width      .46s var(--ap-swipe-ease, cubic-bezier(.2, 1.2, .35, 1));
}
/* The skin stretches, on its own clock. It has to be a second element: scale
   and translate are the same property, so one transform cannot carry a long
   spring for the travel and a short snap for the squash at the same time.
   The origin is the LEADING edge — set by direction — so that edge stays on
   the spring's path and the tail drags behind it, which is the difference
   between a box that grows and a body that is being pulled. */
.ap-tab-ind::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 12px;
  background: #FAF6F1;
  transform: scale(var(--sx, 1), var(--sy, 1));
  transform-origin: var(--ox, 50%) 50%;
  transition: transform .26s cubic-bezier(.34, 1.56, .64, 1);
}
.ap-tab-ind.is-first,
.ap-tab-ind.is-first::before{ transition: none; }

.ap-tab{ position: relative; z-index: 1; }

@media (max-width: 760px){
  .ap-tab-ind{ top: 8px; height: calc(100% - 12px); }
  .ap-tab-ind::before{ border-radius: 9px; }
}
@media (prefers-reduced-motion: reduce){
  .ap-tab-ind, .ap-tab-ind::before{ transition-duration: 0s; }
  .ap-tab-ind::before{ transform: none; }
}
@media (max-width: 760px){
  /* Lower on a phone (12.5%, 32px at 390, asked for twice): at 17.5% the bar
     covered the screen's lower bezel and the stand, and the picture read as
     cut off above it. It now sits clear of the stand, across the keyboard's
     back edge. */
  .ap-tabs{ gap: 4px; padding: 8px; border-radius: 15px; bottom: round(calc(var(--ap-ppl, 100vw) * .125), 8px); }
  .ap-tab{ padding: 8px 12px; font-size: 12.41px; }
}
/* Four labels this long do not fit a phone at any size worth reading them at:
   at 390 the bar came to 418px and lost its end tabs off both edges. It keeps
   the glass and scrolls instead, with a gutter either side so it reads as a
   bar on the page rather than one cut by it. The scrollbar is hidden because
   it would sit across the desk. */
.ap-tabs{
  max-width: calc(100vw - 32px);
  overflow-x: auto;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.ap-tabs::-webkit-scrollbar{ display: none; }
@media (prefers-reduced-motion: reduce){
  .ap-tabs{ transition-duration: 0s; }
}
