/* ============================================================================
   Masroof — spending tracker landing page.

   The page is set like a statement: hairline rules instead of cards, amounts
   right-aligned in tabular mono, running totals under each block. Every figure
   carries three decimals because a rial has a thousand baisa, and that is the
   detail most trackers get wrong.
   ========================================================================= */

:root {
  color-scheme: light dark;

  --ground:   #FFFFFF;
  --surface:  #FFFFFF;
  --sunk:     #EAE8E1;
  --ink:      #101512;
  --ink-soft: #333D38;
  --muted:    #5F6B65;
  --teal:     #0E7C66;
  --teal-deep:#084F41;
  --teal-wash:#DFEEE8;
  --amber:    #A9660F;
  --line:     #DEDBD2;
  --hair:     #C9C5BA;

  --display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --ui:      "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter: clamp(1.25rem, 5vw, 3rem);
  --measure: 33rem;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:   #0B0F0D;
    --surface:  #121815;
    --sunk:     #171E1A;
    --ink:      #E9EFEB;
    --ink-soft: #C3CEC8;
    --muted:    #849A90;
    --teal:     #35C29D;
    --teal-deep:#7BDCC0;
    --teal-wash:#10241E;
    --amber:    #DFA85C;
    --line:     #222C27;
    --hair:     #33403A;
  }
}

:root[data-theme="dark"] {
  --ground:   #0B0F0D;
  --surface:  #121815;
  --sunk:     #171E1A;
  --ink:      #E9EFEB;
  --ink-soft: #C3CEC8;
  --muted:    #849A90;
  --teal:     #35C29D;
  --teal-deep:#7BDCC0;
  --teal-wash:#10241E;
  --amber:    #DFA85C;
  --line:     #222C27;
  --hair:     #33403A;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* MUST be clip, not hidden. `overflow-x: hidden` turns body into a scroll
     container, and once it is one, `position: sticky` inside it sticks to body
     rather than the viewport (so the pinned hero never pins) and the root
     scroll timeline stops driving the capture. `clip` stops sideways overflow
     without creating a scroll container, so both keep working. */
  overflow-x: clip;
}

h1, h2, h3 { margin: 0; font-weight: 400; text-wrap: balance; }
h1, h2 { font-family: var(--display); letter-spacing: -.01em; }
p { margin: 0; }
a { color: inherit; }

.wrap { width: min(100% - var(--gutter) * 2, 64rem); margin-inline: auto; }
.col { max-width: var(--measure); }

.amt {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum"; letter-spacing: -.01em;
}
.eyebrow {
  font-family: var(--mono); font-size: .72rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--teal);
}
.omr { font-size: .55em; color: var(--muted); margin-left: .35em; letter-spacing: .06em; }

/* ---------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--ui); font-size: .95rem; font-weight: 600;
  padding: .8rem 1.4rem; border-radius: 8px; border: 1px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: transform .16s cubic-bezier(.2,.7,.3,1), background-color .16s, border-color .16s, color .16s;
}
.btn-primary { background: var(--teal); color: #F6FBF9; }
:root[data-theme="dark"] .btn-primary { color: #04140F; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .btn-primary { color: #04140F; } }
.btn-primary:hover { transform: translateY(-2px); }
.btn-ghost { border-color: var(--hair); }
.btn-ghost:hover { transform: translateY(-2px); border-color: var(--teal); color: var(--teal); }
a:focus-visible, button:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }

/* ----------------------------------------------------------------- header */

.masthead { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.4rem 0 .25rem; }
.logo { display: flex; align-items: center; gap: .6rem; font-weight: 600; font-size: 1.05rem; letter-spacing: -.01em; }
.logo .mk {
  width: 27px; height: 27px; border-radius: 7px; background: var(--teal); color: #F6FBF9;
  display: grid; place-items: center; font-size: 15px; font-family: Georgia, serif;
}
:root[data-theme="dark"] .logo .mk { color: #04140F; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .logo .mk { color: #04140F; } }
.theme-btn {
  background: none; border: 1px solid var(--line); color: var(--muted);
  font-family: var(--mono); font-size: .72rem; letter-spacing: .08em;
  padding: .4rem .8rem; border-radius: 999px; cursor: pointer;
}
.theme-btn:hover { color: var(--teal); border-color: var(--teal); }

/* ------------------------------------------------------------------- hero */

/* The hero holds the page while the capture plays.

   It is done with sticky elements over a tall runway, never by intercepting the
   wheel: the scrollbar stays honest, Page Down and the keyboard still work, and
   a reader who does not want to watch can flick straight past. The runway only
   exists where the scroll-driven animation exists and motion is welcome —
   otherwise pinning would just be dead scrolling over a finished picture.

   STRUCTURE (rebuilt 2026-09-27). The copy and the phone are separate grid
   items, and only the phone sits inside the runway (.hero-pin):

     desktop  both columns stick side by side for the length of the runway —
              the headline stays beside the phone while the capture plays;
     phone    the copy scrolls by normally, THEN the phone alone takes the
              screen, pins, and plays.

   The old layout pinned the whole hero, copy and phone together, on every
   screen. On a phone that cannot fit: measured in an exact 390x844 frame it was
   923px, and in Safari that phone only shows ~664px with its toolbars up. The
   bottom of a sticky box taller than the screen is never visible while it is
   held, so the confirmation — the point of the whole thing — played off
   screen. Pinning only the phone also lets the mock run at roughly 0.8 scale
   instead of 0.5, which is the difference between readable and decoration. */
.hero-pin { position: relative; }

@supports ((animation-timeline: scroll()) and (animation-range: entry)) {
  @media (prefers-reduced-motion: no-preference) and (min-height: 30rem) {
    .hero-shell { align-items: start; }
    .hero-pin { height: 230vh; }
    .hero-sticky {
      position: sticky; top: 0;
      /* svh = the viewport with the browser's toolbars showing, the smallest it
         ever gets. vh on iOS is the toolbar-HIDDEN height, which is taller than
         the screen a visitor actually sees when the page loads. */
      height: 100vh; height: 100svh;
      /* Centre vertically but STRETCH across: the phone's width is a
         percentage of the stage, and `place-items: center` shrink-wraps the
         stage around the phone, so that percentage resolved against itself and
         the mock collapsed to about 170px wide on desktop. */
      display: grid; align-items: center; justify-items: stretch;
    }

    /* Desktop: the copy sticks beside the phone for the same stretch. Its
       containing block is the grid, whose row is as tall as the runway. */
    @media (min-width: 60rem) {
      .hero-copy {
        align-self: start;
        position: sticky; top: 0;
        height: 100vh; height: 100svh;
        display: flex; align-items: center;
      }
    }

    /* Phones: the phone owns the whole screen, so size it off the screen. */
    @media (max-width: 60rem) {
      .hero-pin { height: 210vh; height: 210svh; }
      .hero-sticky .phone { height: min(64svh, 520px); width: auto; }
      /* Shrink the mock as a whole rather than capping its height: a capped
         height squeezes the contents and `overflow: hidden` clips what no
         longer fits. `zoom` rather than `transform: scale()` because zoom
         shrinks the layout box too, so the stage reserves the right space. */
      @supports (zoom: calc(10px / 5px)) {
        .hero-sticky .phone {
          --pw: 18rem;
          --ph: calc(var(--pw) * 17 / 9);
          width: var(--pw);
          height: auto;
          zoom: calc(min(64svh, 520px) / var(--ph));
        }
      }
      .hero-sticky .stage-foot { margin-top: .9rem; }
    }
  }
}

.hero { padding: clamp(2rem, 5vw, 3.5rem) 0 clamp(3rem, 8vw, 5rem); }
.hero-grid { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); grid-template-columns: 1fr; align-items: center; }
@media (min-width: 60rem) { .hero-grid { grid-template-columns: 1.1fr .9fr; } }

.hero h1 { font-size: clamp(2.7rem, 7.2vw, 4.3rem); line-height: 1.03; margin: 1rem 0 0; }
.hero h1 i { font-style: italic; color: var(--teal); }
.hero-sub { font-size: 1.08rem; color: var(--ink-soft); margin-top: 1.3rem; max-width: 31rem; }
.hero-cta { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 1.9rem; }
.hero-note { margin-top: 1rem; font-family: var(--mono); font-size: .78rem; color: var(--muted); }

/* ------------------------------------------------- the tap (the one moment)

   Resting state is the finished capture — prompts answered, notification
   showing — so every browser gets a complete picture. Where scroll-driven
   animation exists, it rewinds to an untouched lock screen and plays the three
   taps, the four prompts and the confirmation against your scroll. Decorative,
   so it is progressive enhancement with no JS fallback.
   ------------------------------------------------------------------------ */

.phone-stage { display: grid; place-items: center; position: relative; }

.phone {
  position: relative;
  width: min(18rem, 82%);
  aspect-ratio: 9 / 17;
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: 34px;
  box-shadow: 0 2px 4px rgba(16,21,18,.06), 0 40px 80px -30px rgba(16,21,18,.45);
  overflow: hidden;
}

/* Two faces stacked in the same box. The turn is a 2D squeeze on .phone with
   the faces swapped at its narrowest point, not a 3D rotation: preserve-3d plus
   backface-visibility plus the `zoom` the mobile rule applies is exactly the
   combination iOS Safari renders inconsistently, and iPhone owners are the
   entire audience for this page. */
.face { position: absolute; inset: 0; display: flex; flex-direction: column; border-radius: inherit; }
.face-front { z-index: 1; background: var(--surface); }
.face-back {
  z-index: 2;
  opacity: 0; visibility: hidden;          /* at rest the front, finished, is the picture */
  background:
    radial-gradient(130% 60% at 25% 0%, rgba(255,255,255,.55), transparent 62%),
    linear-gradient(165deg, var(--sunk), var(--surface) 48%, var(--sunk));
  align-items: center; justify-content: center;
}
:root[data-theme="dark"] .face-back {
  background: radial-gradient(130% 60% at 25% 0%, rgba(255,255,255,.06), transparent 62%),
              linear-gradient(165deg, #1B2320, var(--surface) 48%, #0F1512);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .face-back {
    background: radial-gradient(130% 60% at 25% 0%, rgba(255,255,255,.06), transparent 62%),
                linear-gradient(165deg, #1B2320, var(--surface) 48%, #0F1512);
  }
}

.cam {
  position: absolute; top: 5%; left: 7%; width: 40%; aspect-ratio: 1;
  display: grid; grid-template-columns: 1fr 1fr; place-items: center; padding: 9%;
  border-radius: 24%; border: 1px solid var(--line);
  background: linear-gradient(145deg, var(--sunk), var(--surface));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.5), 0 1px 3px rgba(16,21,18,.08);
}
.cam .lens {
  width: 82%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle at 36% 34%, #5B6B64 0 10%, #1C2522 26%, #070B09 62%);
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--hair);
}
.cam .lens.small { width: 48%; }
.cam .flash { width: 24%; aspect-ratio: 1; border-radius: 50%; background: #F1E6C6; box-shadow: 0 0 0 2px var(--hair); }

/* The app's own mark where a phone maker would put theirs — it is the gesture
   that is iPhone's, not the object. */
.back-mark { font-family: Georgia, "Times New Roman", serif; font-size: 3.4rem; line-height: 1; color: var(--ink); opacity: .09; }

.tap-count {
  position: absolute; left: 0; right: 0; bottom: 14%;
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
}
.tap-count .dots { display: inline-flex; gap: 9px; }
.tap-count .dots i { display: block; width: 9px; height: 9px; border-radius: 50%; background: var(--hair); }
.tap-count .lbl {
  font-family: var(--mono); font-size: .6rem; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted);
}
:root[data-theme="dark"] .phone { box-shadow: 0 2px 4px rgba(0,0,0,.6), 0 40px 80px -30px rgba(0,0,0,.9); }

.phone-top {
  height: 26px; flex: none; display: grid; place-items: center; padding-top: 6px;
}
.phone-top span { width: 62px; height: 5px; border-radius: 99px; background: var(--line); }

.lock { padding: 1.4rem 1.15rem 0; text-align: center; flex: none; }
.lock .time { font-family: var(--mono); font-size: 2.5rem; line-height: 1; letter-spacing: -.03em; }
.lock .date { font-size: .74rem; color: var(--muted); margin-top: .3rem; }

/* ripples from the three taps, centred on the mark on the back */
.taps { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.tap {
  position: absolute; left: 50%; top: 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px;
  border-radius: 50%; border: 1.5px solid var(--teal); opacity: 0; transform: scale(.3);
}

/* The three questions share ONE slot rather than stacking into a list. Two
   reasons. A real Shortcut replaces each question with the next, so this is
   what the gesture actually looks like. And stacked, the three of them plus the
   lock screen and the confirmation were taller than the mock phone on a
   phone-sized screen — `overflow: hidden` then clipped everything below the
   first question, so scrolling played an animation nobody could see. Later
   prompts paint over earlier ones by DOM order, and the backgrounds are opaque,
   so the hand-over reads as a replacement with a short cross-fade. */
.prompts { position: relative; padding: 1rem .8rem; min-height: 5.9rem; flex: none; }
.prompt {
  position: absolute; left: .8rem; right: .8rem; top: 1rem;
  background: var(--sunk); border: 1px solid var(--line); border-radius: 12px;
  padding: .6rem .7rem; text-align: left;
}
.prompt .q { font-size: .68rem; color: var(--muted); letter-spacing: .04em; }
.prompt .a { font-family: var(--mono); font-size: .95rem; margin-top: .15rem; }
.prompt .a.big { font-size: 1.3rem; }

.banner {
  margin: auto .8rem 1.1rem; padding: .7rem .8rem;
  background: var(--teal-wash); border: 1px solid var(--teal); border-radius: 12px;
  display: flex; align-items: center; gap: .6rem;
}
.banner .ic {
  width: 24px; height: 24px; border-radius: 6px; background: var(--teal); color: #F6FBF9;
  display: grid; place-items: center; font-size: 13px; flex: none; font-family: Georgia, serif;
}
:root[data-theme="dark"] .banner .ic { color: #04140F; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .banner .ic { color: #04140F; } }
.banner .txt { font-size: .74rem; line-height: 1.3; }
.banner .txt b { display: block; font-family: var(--mono); font-size: .84rem; font-weight: 500; }

/* The hint and the month total share one slot: the hint says "scroll", then
   gives way to the total that the capture is about to change. Sharing the slot
   keeps the pinned hero exactly one screen tall on a phone. */
.stage-foot { display: grid; margin-top: 1rem; }
.stage-foot > * { grid-area: 1 / 1; justify-self: center; align-self: center; }

.stage-hint {
  margin: 0; font-family: var(--mono); font-size: .7rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  /* Hidden at rest: with no animation there is nothing to scroll for, and
     telling a reduced-motion visitor to "watch" something that never moves is
     worse than saying nothing. The animation below brings it in. */
  opacity: 0;
}

.tally-chip {
  display: inline-flex; align-items: baseline; gap: .5rem;
  padding: .42rem .85rem; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-family: var(--mono);
}
.tally-chip .lbl { font-size: .62rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.tally-chip .val { display: inline-grid; font-size: .95rem; font-weight: 500; font-variant-numeric: tabular-nums; }
.tally-chip .t-old, .tally-chip .t-new { grid-area: 1 / 1; }
.tally-chip .t-old { opacity: 0; }        /* at rest: the finished month */
.tally-chip .cur { font-size: .66rem; color: var(--muted); letter-spacing: .06em; }

@supports ((animation-timeline: scroll()) and (animation-range: entry)) {
  @media (prefers-reduced-motion: no-preference) {
    /* Ranges are spread across the pinned runway (230vh tall, so roughly 130vh
       of scrolling happens while the hero is held) and finish with a beat to
       spare, so the capture is complete before the page moves on. */
    /* A `vh` here is a distance along the root scroll timeline, and it does NOT
       come out as one viewport-height of scrolling — measured against
       screenshots, the capture finished around halfway through the pin when the
       last range ended at 102vh, leaving the second half of the runway showing a
       finished picture. These values are the old ones stretched by half again,
       which lands the confirmation at roughly four fifths of the way through the
       pin: complete before the hero lets go, with a beat to read it. Change them
       by screenshot, never by getComputedStyle or getComputedTiming — both keep
       reporting the resting state while the compositor draws something else. */
    /* SUPERSEDED 2026-09-27. The ranges used to be `scroll(root block)` with vh
       offsets, and those were tuned against a browser emulator whose CSS
       viewport (844px) did not match its window (1241px). Stretched to fit that
       mismatch, the confirmation ended at 153vh — past the point where a REAL
       phone's pin lets go (~120vh on mobile, ~130vh on desktop), so on an actual
       iPhone the "saved" banner played while the hero was already scrolling
       away.

       Now every range is a percentage of `contain` on a view timeline attached
       to .hero-pin. For a subject taller than the viewport, `contain` runs from
       the pin's top meeting the top of the screen to its bottom meeting the
       bottom — which is precisely the interval the sticky hero is held. So 0%
       is "pinned", 100% is "about to release", on every device, whatever the
       viewport, the masthead height or the runway length. Retune in % only. */
    .hero-pin { view-timeline: --pin block; }

    /* 1 — the back: three taps, each lighting a dot */
    .tap { animation: tap-ring linear both; animation-timeline: --pin; }
    .tap:nth-child(1) { animation-range: contain 3%  contain 14%; }
    .tap:nth-child(2) { animation-range: contain 9%  contain 20%; }
    .tap:nth-child(3) { animation-range: contain 15% contain 26%; }
    .tap-count .dots i { animation: dot-on linear both; animation-timeline: --pin; }
    .tap-count .dots i:nth-child(1) { animation-range: contain 5%  contain 8%; }
    .tap-count .dots i:nth-child(2) { animation-range: contain 11% contain 14%; }
    .tap-count .dots i:nth-child(3) { animation-range: contain 17% contain 20%; }

    /* 2 — it turns over: squeeze to an edge, swap faces at the narrowest point */
    .phone      { animation: turn     linear both; animation-timeline: --pin; animation-range: contain 29% contain 39%; }
    .face-back  { animation: back-out linear both; animation-timeline: --pin; animation-range: contain 29% contain 39%; }
    .face-front { animation: front-in linear both; animation-timeline: --pin; animation-range: contain 29% contain 39%; }

    /* 3 — the four prompts replace one another, then the confirmation */
    .lock   { animation: lock-out  linear both; animation-timeline: --pin; animation-range: contain 42% contain 48%; }
    .prompt { animation: prompt-in linear both; animation-timeline: --pin; }
    .prompt:nth-child(1) { animation-range: contain 45% contain 52%; }
    .prompt:nth-child(2) { animation-range: contain 52% contain 59%; }
    .prompt:nth-child(3) { animation-range: contain 59% contain 66%; }
    .prompt:nth-child(4) { animation-range: contain 66% contain 73%; }
    .banner { animation: banner-in linear both; animation-timeline: --pin; animation-range: contain 73% contain 81%; }

    /* 4 — it lands in the month. The hint hands its slot to the running total,
       which then ticks from 391.400 to 403.900. Everything is done by 88%, so
       the finished frame holds for the last stretch of the pin. */
    .stage-hint { animation: hint-out  linear both; animation-timeline: --pin; animation-range: contain 22% contain 30%; }
    .tally-chip { animation: chip-in   linear both; animation-timeline: --pin; animation-range: contain 30% contain 36%; }
    .t-old      { animation: tally-old linear both; animation-timeline: --pin; animation-range: contain 81% contain 87%; }
    .t-new      { animation: tally-new linear both; animation-timeline: --pin; animation-range: contain 81% contain 87%; }
    .tally-chip .val { animation: chip-flash linear both; animation-timeline: --pin; animation-range: contain 81% contain 90%; }
  }
}

@keyframes dot-on {
  from { background: var(--hair); transform: scale(.8); }
  to   { background: var(--teal); transform: scale(1.15); }
}
@keyframes turn {
  0%   { transform: scaleX(1); }
  50%  { transform: scaleX(.035); }
  100% { transform: scaleX(1); }
}
@keyframes back-out {
  0%, 49.9%  { opacity: 1; visibility: visible; }
  50%, 100%  { opacity: 0; visibility: hidden; }
}
@keyframes front-in {
  0%, 49.9%  { opacity: 0; }
  50%, 100%  { opacity: 1; }
}
@keyframes chip-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes tally-old {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-9px); }
}
@keyframes tally-new {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@keyframes chip-flash {
  0%, 100% { color: var(--ink); }
  35%      { color: var(--teal); }
}

@keyframes tap-ring {
  0%   { opacity: 0; transform: scale(.3); }
  35%  { opacity: .85; }
  100% { opacity: 0; transform: scale(4.4); }
}
@keyframes prompt-in {
  0%   { opacity: 0; transform: translateY(14px) scale(.97); }
  100% { opacity: 1; transform: none; }
}
@keyframes banner-in {
  0%   { opacity: 0; transform: translateY(16px); }
  100% { opacity: 1; transform: none; }
}
@keyframes lock-out {
  0%   { opacity: 1; }
  100% { opacity: .28; }
}
@keyframes hint-out {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}

/* --------------------------------------------------------------- sections */

.section { padding: clamp(3.5rem, 8vw, 5.5rem) 0; border-top: 1px solid var(--line); }
.section-head { margin-bottom: clamp(2rem, 5vw, 3rem); }
.section-head h2 { font-size: clamp(1.9rem, 4.4vw, 2.8rem); line-height: 1.08; margin-top: .55rem; }
.section-head p { color: var(--muted); margin-top: .85rem; max-width: var(--measure); }

/* the four seconds — a genuine ordered sequence, so it is numbered */
.beats { border-top: 1px solid var(--line); }
.beat {
  display: grid; grid-template-columns: 2.5rem 1fr; gap: .3rem 1.25rem;
  padding: 1.35rem 0; border-bottom: 1px solid var(--line); align-items: start;
}
@media (min-width: 46rem) { .beat { grid-template-columns: 2.5rem 13rem 1fr; align-items: baseline; } }
.beat .n { font-family: var(--mono); font-size: .8rem; color: var(--teal); letter-spacing: .06em; grid-row: span 2; }
@media (min-width: 46rem) { .beat .n { grid-row: auto; } }
.beat h3 { font-family: var(--ui); font-size: 1.05rem; font-weight: 600; }
.beat p { color: var(--muted); font-size: .93rem; }

/* --------------------------------------------------------------- statement */

.statement { display: grid; gap: clamp(2rem, 5vw, 3rem); grid-template-columns: minmax(0, 1fr); }
/* Grid items otherwise keep the setup path's intrinsic width, widening the
   entire document and making iPhone browsers shrink the hero to fit. */
.statement > * { min-width: 0; }
@media (min-width: 58rem) { .statement { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); align-items: start; } }

.ledger { border-top: 1px solid var(--hair); }
.ledger-row {
  display: grid; grid-template-columns: 1fr auto; gap: .2rem 1rem;
  padding: .8rem 0; border-bottom: 1px solid var(--line); align-items: baseline;
}
.ledger-row .what { font-weight: 500; }
.ledger-row .when { font-size: .78rem; color: var(--muted); font-family: var(--mono); }
.ledger-row .val { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 1rem; grid-row: span 2; align-self: center; }
.ledger-total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: 1rem 0; border-bottom: 2px solid var(--ink);
}
.ledger-total .k { font-family: var(--mono); font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.ledger-total .v { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 1.5rem; }
.ledger-cap { font-family: var(--mono); font-size: .7rem; color: var(--muted); margin-top: .7rem; letter-spacing: .04em; }

/* category bars */
.cats { display: flex; flex-direction: column; gap: .85rem; }
.cat .top { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; font-size: .88rem; }
.cat .top .v { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.cat .track { height: 7px; background: var(--sunk); border-radius: 99px; margin-top: .35rem; overflow: hidden; }
.cat .fill { height: 100%; background: var(--teal); border-radius: 99px; transform-origin: left center; transform: scaleX(var(--p, 0)); }
/* The bars grow when their block reveals, driven by the wrapper's .shown so the
   transition has a state change to animate from. Without JS the base rule above
   already draws them at full length. */
.js-motion [data-reveal] .cat .fill { transform: scaleX(0); }
.js-motion [data-reveal].shown .cat .fill {
  transform: scaleX(var(--p, 0));
  transition: transform .9s cubic-bezier(.2,.7,.3,1) var(--bd, 0ms);
}
.cat:nth-child(2) .fill { background: var(--teal-deep); }
.cat:nth-child(3) .fill { background: var(--amber); }

/* ---------------------------------------------------------------- details */

.details { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
@media (min-width: 42rem) { .details { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62rem) { .details { grid-template-columns: repeat(3, 1fr); } }
.detail { background: var(--ground); padding: 1.4rem 1.3rem; }
.detail h3 { font-family: var(--ui); font-size: .95rem; font-weight: 600; }
.detail p { color: var(--muted); font-size: .89rem; margin-top: .35rem; }
.detail .fig { font-family: var(--mono); color: var(--teal); font-size: .85rem; }

/* ------------------------------------------------------------------ setup */

.setup { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: clamp(1.5rem, 4vw, 2.25rem); }
.path {
  font-family: var(--mono); font-size: .82rem; line-height: 2;
  color: var(--ink-soft); background: var(--sunk); border: 1px solid var(--line);
  border-radius: 10px; padding: .8rem 1rem; margin-top: 1rem;
  white-space: normal; overflow-wrap: anywhere;
}
.path b { color: var(--teal); font-weight: 500; }

.honest { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
.honest h3 { font-family: var(--ui); font-size: .85rem; font-weight: 600; letter-spacing: .02em; color: var(--muted); }
.honest ul { list-style: none; margin: .6rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; font-size: .89rem; color: var(--muted); }
.honest li { display: flex; gap: .6rem; }
.honest li::before { content: "·"; color: var(--amber); font-weight: 700; }

/* ----------------------------------------------------------------- closer */

.closer { text-align: center; padding: clamp(4rem, 9vw, 6.5rem) 0; border-top: 1px solid var(--line); }
.closer h2 { font-size: clamp(2rem, 5.6vw, 3rem); line-height: 1.06; }
.closer p { color: var(--muted); margin-top: .9rem; }
.closer .hero-cta { justify-content: center; }

.foot { border-top: 1px solid var(--line); padding: 1.75rem 0 3rem; display: flex; flex-wrap: wrap; gap: .6rem 1.5rem; justify-content: space-between; align-items: center; font-family: var(--mono); font-size: .74rem; color: var(--muted); }
.foot a { text-decoration: none; }
.foot a:hover { color: var(--teal); }

/* ---------------------------------------------------------------- reveals */

.js-motion [data-reveal] { opacity: 0; transform: translateY(16px); }
.js-motion [data-reveal].shown {
  opacity: 1; transform: none;
  transition: opacity .65s cubic-bezier(.2,.7,.3,1), transform .65s cubic-bezier(.2,.7,.3,1);
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}

.life-photo{max-width:1120px;margin:80px auto;display:grid;grid-template-columns:1.2fr 1fr;gap:48px;padding:0 24px;align-items:center}.life-photo img{width:100%;height:auto;aspect-ratio:3/2;object-fit:cover;border-radius:20px}.life-photo h2{font-family:"Instrument Serif",serif;font-size:clamp(36px,4vw,58px);line-height:1.08;font-weight:400;margin:18px 0}.life-photo p{line-height:1.7;color:var(--muted);margin-bottom:24px}.life-photo .btn{margin:4px 0}@media(max-width:700px){.life-photo{grid-template-columns:1fr;gap:22px;margin:50px auto}}

/* Bright Masroof identity: image edges stay crisp in both themes. */
.logo img.mk{width:36px;height:36px;flex:none;display:block;object-fit:contain;border-radius:10px;background:#FFFFFF}
.banner img.ic{display:block;object-fit:contain;background:#FFFFFF;padding:0}
