:root {
  --font-size-micro: 12px;
  --font-size-caption: 14px;
  --font-size-body: 17px;
  --font-size-body-large: 20px;
  --font-size-title: 24px;
  --font-size-headline: 29px;
  --font-size-display: 35px;
  --font-size-hero: 42px;
  --line-height-tight: 1.15;
  --line-height-snug: 1.3;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.65;
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-heavy: 800;
  --letter-spacing-display: -0.03em;
  --letter-spacing-title: -0.02em;
  --letter-spacing-body: 0em;
  --letter-spacing-label: 0.08em;
  --space-none: 0px;
  --space-xxs: 2px;
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 12px;
  --space-lg: 16px;
  --space-xl: 24px;
  --space-xxl: 32px;
  --space-xxxl: 48px;
  --space-huge: 64px;
  --radius-none: 0px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 999px;
  --duration-instant: 90ms;
  --duration-quick: 160ms;
  --duration-settled: 240ms;
  --easing-standard: cubic-bezier(0.2, 0, 0, 1);
  --easing-enter: cubic-bezier(0, 0, 0, 1);
  --easing-exit: cubic-bezier(0.3, 0, 1, 1);
  --font-feature-tabular: 'tnum' 1, 'lnum' 1;

  --color-background: #0B0D12;
  --color-surface: #12151C;
  --color-surface-raised: #191D26;
  --color-border: #232833;
  --color-border-strong: #333A48;
  --color-text: #EDEFF3;
  --color-text-muted: #B4BBC8;
  --color-text-faint: #6B7484;
  --color-accent: #E8A34B;
  --color-accent-text: #F0C078;
  --color-on-accent: #0B0D12;
  --color-positive: #79C68D;
  --color-negative: #E28472;
  --color-caution: #EAC451;
  --color-info: #7FB6E8;
  --color-focus-ring: #F0C078;
}

@media (prefers-color-scheme: light) {
  :root {
  --color-background: #F4F5F8;
  --color-surface: #FFFFFF;
  --color-surface-raised: #FAFBFC;
  --color-border: #DCE0E7;
  --color-border-strong: #BFC5D0;
  --color-text: #12151C;
  --color-text-muted: #454C5A;
  --color-text-faint: #69707E;
  --color-accent: #A85E12;
  --color-accent-text: #5C3208;
  --color-on-accent: #FFFFFF;
  --color-positive: #2E7D46;
  --color-negative: #7E2113;
  --color-caution: #7A5A05;
  --color-info: #1A5285;
  --color-focus-ring: #A85E12;
  }
}

:root[data-theme='dark'] {
  --color-background: #0B0D12;
  --color-surface: #12151C;
  --color-surface-raised: #191D26;
  --color-border: #232833;
  --color-border-strong: #333A48;
  --color-text: #EDEFF3;
  --color-text-muted: #B4BBC8;
  --color-text-faint: #6B7484;
  --color-accent: #E8A34B;
  --color-accent-text: #F0C078;
  --color-on-accent: #0B0D12;
  --color-positive: #79C68D;
  --color-negative: #E28472;
  --color-caution: #EAC451;
  --color-info: #7FB6E8;
  --color-focus-ring: #F0C078;
}

:root[data-theme='light'] {
  --color-background: #F4F5F8;
  --color-surface: #FFFFFF;
  --color-surface-raised: #FAFBFC;
  --color-border: #DCE0E7;
  --color-border-strong: #BFC5D0;
  --color-text: #12151C;
  --color-text-muted: #454C5A;
  --color-text-faint: #69707E;
  --color-accent: #A85E12;
  --color-accent-text: #5C3208;
  --color-on-accent: #FFFFFF;
  --color-positive: #2E7D46;
  --color-negative: #7E2113;
  --color-caution: #7A5A05;
  --color-info: #1A5285;
  --color-focus-ring: #A85E12;
}

/* Motion is confirmation, not decoration — so removing it costs nothing. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}



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

/* hidden must actually hide.
   The browser's own rule is [hidden] { display: none }, at attribute
   specificity — so any rule of ours that sets display with a class or an
   element name outranks it, and the element stays on screen with hidden set to
   true. That is not theoretical: on 10 August 2026 fieldset.step { display:
   flex } beat it, and all four pages of the sign-up form rendered at once with
   three of them marked hidden. No test caught it, because the unit tests drive
   a fake DOM that has no CSS at all; it was found by opening the page.
   !important here so the JS is the thing that decides, always, whatever anybody
   styles later. */
[hidden] { display: none !important; }

:root {
  /* Tall enough for a 48px target plus its padding, and the space .screen
     reserves so the disclosure is never underneath it. */
  --tab-bar-height: 72px;
}

html {
  /* Prevents iOS inflating text in landscape, which breaks the hero number. */
  -webkit-text-size-adjust: 100%;
  background: var(--color-background);
}

body {
  margin: 0;
  /* The system stack. No webfont: 30-100KB before first paint is the difference
     between instant and broken on these connections, and this list already
     carries Devanagari for the Hindi copy. */
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans",
               "Noto Sans Devanagari", sans-serif;
  font-size: var(--font-size-body);
  line-height: var(--line-height-normal);
  color: var(--color-text);
  background: var(--color-background);
  /* Respects the notch without pushing content off a phone that has none. */
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/**
 * A phone column on a phone, a page on a laptop.
 *
 * 34rem is the right measure for a form on a ₹7,000 Android and wrong for a
 * 15-inch screen, where it renders as a narrow strip down the middle of a white
 * field and reads as a broken mobile site rather than a deliberate one.
 *
 * The marketing site solves this with a 1240px wrap and text held to ch
 * measures, and that is the pattern followed here: the *shell* widens with the
 * viewport, individual blocks stay readable. A form input stretched to 1240px
 * would be worse than the strip — nobody can track a label that far from its
 * field — so inputs keep their own measure inside the wider frame.
 */
.screen {
  max-width: 34rem;
  margin: 0 auto;
  /* The last value clears the sticky tab bar; without it the bar sits over the
     final line of the disclosure. */
  padding: var(--space-lg) var(--space-md) var(--tab-bar-height);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  min-height: 100dvh;
}

/* The brand panel is a desktop-only thing. Below 64rem it does not exist. */
/**
 * The firm's mark, on the screen somebody lands on.
 *
 * Sized in rem so it tracks the type scale rather than the device's pixel
 * ratio, and capped against the column so it cannot overflow on a narrow
 * phone. A height of auto, with the intrinsic width and height set on the
 * element itself, keeps the aspect ratio and reserves the space before the
 * file arrives — so the form below does not jump under somebody's thumb.
 *
 * (No backticks in here. This block is inside an unquoted template literal,
 * and prose written in the Markdown habit of quoting identifiers would be
 * executed as a command substitution. It has taken production down once.)
 */
.greet--mark { line-height: 0; }

.mark {
  display: block;
  width: 9rem;
  max-width: 60%;
  height: auto;
}

.brandpane { display: none; }

/* Tablet: the column earns a little more room before the layout changes. */
@media (min-width: 48rem) {
  .screen {
    max-width: 40rem;
    padding: var(--space-xl) var(--space-lg) var(--tab-bar-height);
  }
}

/**
 * Laptop and up: two panes, because one column was never going to look right.
 *
 * Two earlier attempts adjusted the width of a single column — first stretching
 * it to the marketing site's 1240px wrap, then centring it. The first left a
 * form sitting in the corner of an empty page; the second left a narrow strip
 * with a dead gap down the middle of the window. The column was not the
 * problem. There was nothing beside it.
 *
 * So the shell becomes a grid: the product on the left, the thing you came to
 * do on the right. The left pane is fixed and calm, the right one holds the
 * interaction at a width a form should actually be. Both panes are full height,
 * so nothing floats in an empty field.
 */
@media (min-width: 64rem) {
  .shell {
    display: grid;
    grid-template-columns: minmax(20rem, 34rem) minmax(28rem, 1fr);
    gap: 0;
    min-height: 100dvh;
    max-width: 82rem;
    margin: 0 auto;
  }

  /**
   * The bar sits under the screen column, not across the whole window.
   *
   * It is a sibling of .shell, not a child of the column, so it cannot
   * inherit the grid. These two margins reproduce the grid's arithmetic: the
   * shell is centred at 82rem, and at any width from 64rem up its first
   * column is its full 34rem (the second column's minimum leaves room). With
   * one button this was wrong too and nobody saw it; with three, "Home" sat
   * under the brand panel.
   */
  .tabs {
    margin-left: calc(max(0px, (100vw - 82rem) / 2) + 34rem);
    margin-right: calc(max(0px, (100vw - 82rem) / 2));
    border-left: 1px solid var(--color-border);
  }

  /**
   * What must not grow with the column.
   *
   * A label loses its field at this width, and a line of body text stops
   * being readable well before it — which is the reason the column used to
   * be capped at all. Capping the controls instead keeps the frame wide and
   * the content legible, which is what the header comment describes.
   */
  .screen input,
  .screen select,
  .screen textarea,
  /**
   * The primary action, which was missing and is the one you see first.
   *
   * Every control in this list was capped and the button was not, so on a wide
   * window "Send code" ran the full column while the field above it stopped at
   * 34rem — a button roughly three times the width of its own input, which is
   * what a person notices before anything else on the landing screen.
   */
  .screen button,
  .screen .help,
  .screen .note,
  .screen .lede,
  /**
   * Singular, and the plural written here matched nothing.
   *
   * No element in this app has ever carried a class of "disclosures" — the
   * footer that the disclosures() helper builds carries class="disclosure". The cap
   * written specifically for the prescribed market-risk sentence has never
   * applied, and that paragraph has run the full width of the column on every
   * desktop since the two-pane layout shipped. It is the longest text on the
   * screen and the one a regulator cares most about being readable.
   *
   * A CSS selector that matches nothing fails in complete silence: the build
   * passes, the page renders, and the only symptom is a line of text too long
   * to read comfortably.
   */
  .screen .disclosure { max-width: 34rem; }

  .brandpane {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--space-xl);
    /* A hairline rather than a filled block: the palette is already dark, and a
       second surface behind text this size muddies it. */
    border-right: 1px solid var(--color-border);
  }

  .brandpane-mark {
    font-size: var(--font-size-title);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-title);
  }

  .brandpane-line {
    font-size: var(--font-size-headline);
    color: var(--color-text);
  }

  .brandpane-note {
    font-size: var(--font-size-body);
    color: var(--color-text-muted);
    max-width: 34ch;
  }

  /**
   * No measure cap on the registration line.
   *
   * 34ch is right for a sentence and wrong for an identifier: it split
   * "ARN 327798" across two lines, leaving the number stranded on its own. An
   * ARN is one token — the thing a regulator, a client or a complaint refers
   * to — and a reader should never have to reassemble it. The name and the ARN
   * are bound with a non-breaking space in screens.ts for the same reason.
   */
  .brandpane-arn {
    font-size: var(--font-size-body);
    color: var(--color-text-muted);
    margin-top: var(--space-md);
  }

  .screen {
    /**
     * The column fills its pane; the blocks inside keep their measure.
     *
     * This said 34rem, which is the *brand pane's* width, not this one's.
     * The grid gives this column minmax(28rem, 1fr) — 768px in a 1680px
     * window — and capping the content at 544px left 224px of the pane dead,
     * on top of the 184px outside the centred shell. On a laptop that reads
     * as a page that failed to load its right-hand side. Reported 24 August
     * 2026 with a screenshot.
     *
     * The file's own opening comment already stated the rule this restores:
     * "the *shell* widens with the viewport, individual blocks stay
     * readable". Widening the column is safe precisely because the things
     * that must not stretch — inputs, selects, the disclosure text — carry
     * their own measure below.
     */
    max-width: none;
    margin: 0;
    min-height: 100dvh;
    /**
     * The last value clears the tab bar, and dropping it was a regression with
     * teeth: the bar is sticky, so it sat over the final lines of the risk and
     * role disclosures. Those are mandated text — "set to be read" is not
     * satisfied by text a fixed element covers, and somebody had to scroll to
     * find it wedged behind the Withdraw tab. The phone rule always had this
     * padding; the desktop rule was written without it.
     */
    padding: var(--space-xl) var(--space-xl) var(--tab-bar-height);
    justify-content: safe center;
  }

  /* The screen already carries the product name on the left pane. Repeating it
     a hand's width away is the kind of duplication that reads as a mistake. */
  .screen > .brand { display: none; }
}

/**
 * Holds an identifier together without altering the text.
 *
 * The ARN was splitting across lines, leaving its number stranded — and an ARN
 * is one token, the thing a regulator or a complaint refers to. The first fix
 * bound it with a non-breaking space, which changes the *text* to U+00A0 and
 * broke a test asserting the screen contains "ARN 327798". That test was right:
 * a compliance check reading the DOM would have missed it too. Wrapping only
 * the identifier keeps the firm name free to wrap and leaves the characters
 * exactly as written.
 */
.nowrap { white-space: nowrap; }

h1, h2 { margin: 0; font-weight: var(--font-weight-semibold); letter-spacing: var(--letter-spacing-title); }
h1 { font-size: var(--font-size-title); line-height: var(--line-height-snug); }
h2 { font-size: var(--font-size-headline); }
p { margin: 0; }

/* The hero is the amount invested. Tabular figures so it does not jitter as
   digits change — a number that shifts while you look at it reads as unstable,
   which is the opposite of what this screen is for. */
.hero {
  font-size: var(--font-size-display);
  line-height: var(--line-height-tight);
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--font-feature-tabular);
  letter-spacing: var(--letter-spacing-display);
}

.label {
  font-size: var(--font-size-caption);
  letter-spacing: var(--letter-spacing-label);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.lede { font-size: var(--font-size-body-large); color: var(--color-text-muted); }
.secondary { color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.help { font-size: var(--font-size-caption); color: var(--color-text-muted); }

form { display: flex; flex-direction: column; gap: var(--space-sm); }

label {
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);
  font-weight: var(--font-weight-medium);
}

input {
  /* 16px minimum, or iOS zooms the whole page on focus and the layout jumps. */
  font-size: max(16px, var(--font-size-body));
  font-family: inherit;
  min-height: 48px;
  padding: 0 var(--space-md);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

/* A select is an input with a list; it was the one control left to the
   browser's own white box on a dark screen. */
select {
  font-size: max(16px, var(--font-size-body));
  font-family: inherit;
  min-height: 48px;
  padding: 0 var(--space-md);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

input:focus-visible, select:focus-visible, button:focus-visible, a.primary:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

button, a.primary {
  font-family: inherit;
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-semibold);
  /* 48px is the floor for a tap target here. Smaller is a mis-tap on a cracked
     screen, and a mis-tap on this app can be somebody's money. */
  min-height: 48px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: opacity var(--duration-quick) var(--easing-standard);
}

.primary { background: var(--color-accent); color: var(--color-on-accent); }
.primary:disabled { opacity: 0.6; cursor: progress; }

/* The two steps that happen on NSE's site render their action as an anchor
   rather than a button, because they navigate somewhere real. Everything above
   that gives a button its shape is on the element selector, so an anchor would
   otherwise be a run of coloured inline text with no tap target — on the two
   screens where failing to press it means the sign-up never completes.
   inline-flex with centring reproduces the button box; min-height alone does
   not centre the label. */
a.primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  text-decoration: none;
  box-sizing: border-box;
  padding: 0 var(--space-md);
}

.link {
  background: none;
  border: none;
  color: var(--color-accent);
  text-decoration: underline;
  min-height: 44px;
}

.error {
  color: var(--color-negative);
  font-size: var(--font-size-caption);
  /* [hidden] loses to display:flex without this, and the error would show
     permanently. */
}
.error[hidden] { display: none; }

.rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-xs); }
.row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--color-border);
}
.row__amount { font-variant-numeric: tabular-nums; }
.row__status { color: var(--color-text-muted); }

/* Account: a short list of facts, label over value, same row shape as a statement. */
.details { margin: 0; display: flex; flex-direction: column; gap: var(--space-xs); }
.details div {
  display: flex; justify-content: space-between; gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--color-surface-raised); border-radius: var(--radius-md);
}
.details dt { color: var(--color-text-muted); }
.details dd { margin: 0; font-variant-numeric: tabular-nums; }

/* The figures. SVG stretches to the text column; heights are fixed so the
   layout cannot jump as data arrives. Fill colours are tokens, so the contrast
   suite already governs them. */
.figure { margin: 0; display: flex; flex-direction: column; gap: var(--space-xs); }
.figure svg { width: 100%; display: block; }

/* The two bars: name, track, amount. A grid rather than flex so both rows
   share one column layout — the two amounts line up on the right, which is
   what makes the comparison readable at a glance. */
.figure--bars > div { display: flex; flex-direction: column; gap: var(--space-xs); }
.bar {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  align-items: center;
  gap: var(--space-sm);
}
.bar__name { font-size: var(--font-size-caption); color: var(--color-text-muted); }
.bar__track { background: var(--color-surface); border-radius: 999px; height: 10px; overflow: hidden; }
.bar__fill { display: block; height: 100%; border-radius: 999px; }
.bar__fill--in { background: var(--color-text-muted); }
.bar__fill--up { background: var(--color-accent); }
.bar__fill--down { background: var(--color-negative); }
.bar__value { font-variant-numeric: tabular-nums; font-size: var(--font-size-body); }

.figure svg[viewBox$=" 4"] { height: 14px; }
.figure svg[viewBox="0 0 100 26"] { height: 52px; }

/* Today's receipt. The mark carries the state for greyscale; the colour is
   reinforcement, not the message. */
.receipt { font-size: var(--font-size-body); display: flex; gap: var(--space-xs); align-items: baseline; }
.receipt--collected { color: var(--color-text); }
.receipt--pending { color: var(--color-text-muted); }
.receipt--failed { color: var(--color-negative); }
.receipt--next { color: var(--color-text); }

/* The nomination choice.

   Borderless, because a bordered fieldset renders its legend *on* the border
   and only cuts the border for the legend's first line — this question wraps to
   two on a 375px screen, so the second line struck through the box. It was also
   the only label on the form not flush left, since a legend is inset by the
   fieldset's padding.

   So the group is styled as every other field is: a caption-sized question,
   then its answers beneath. The fieldset and legend elements stay for the
   semantics — a screen reader announces the question with each option — and
   give up only the decoration that was breaking.

   (No backticks in this comment: the whole stylesheet is a template literal,
   and one would end it. That is the second time.)

   Radios get the full 48px row so the tap target is the whole label, not the
   16px circle: the same rule as every other control here. */
fieldset.choice {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* One page of the sign-up form. A fieldset because that is what a named group
   of related inputs is, and because the legend then names the group to a screen
   reader rather than being a heading that happens to sit above it.

   min-width: 0 is not decoration: a fieldset has an automatic minimum content
   size, and without this a long option or a wide select pushes the whole page
   wider than the phone and the layout scrolls sideways. */
fieldset.step {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

fieldset.step legend {
  float: left;
  width: 100%;
  padding: 0;
  margin-bottom: var(--space-sm);
  font-size: var(--font-size-title);
  font-weight: var(--font-weight-semibold);
}

/* Back beside Continue, with Continue the wide one. Back is deliberately the
   quieter control: on a form somebody is part-way through, the loud button
   should be the one that finishes it. */
.step-nav {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.step-nav .primary { flex: 1; }
fieldset.choice legend {
  /* Floated rather than display:block: a legend is not an ordinary box, and
     floating it is what makes it flow like one across browsers. */
  float: left;
  width: 100%;
  padding: 0;
  margin-bottom: var(--space-xs);
  font-size: var(--font-size-caption);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-muted);
}
/* Clears the floated legend so the options start below it, not beside it. */
fieldset.choice legend + * { clear: both; }
label.radio {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: 48px;
  font-size: var(--font-size-body);
  color: var(--color-text);
  font-weight: var(--font-weight-regular, 400);
}
label.radio input { min-height: 0; width: 20px; height: 20px; accent-color: var(--color-accent); }

/* A consent is a sentence with a box, not a word with a box, so the control
   sits at the top of the text rather than centred against three lines of it.
   Everything else mirrors label.radio — including min-height on the *label*
   and the reset on the input, which is what stops a 20px box inheriting the
   48px rule the text fields use. */
label.consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  min-height: 48px;
  margin-top: var(--space-md);
  font-size: var(--font-size-body);
  color: var(--color-text);
  font-weight: var(--font-weight-regular, 400);
}
label.consent input {
  min-height: 0;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  flex: 0 0 auto;
  accent-color: var(--color-accent);
}
/* The regulatory sentence under the first box. Indented to the text above it
   so it reads as belonging to that statement rather than to the next one. */
.consent-detail { margin-left: calc(20px + var(--space-sm)); }
.consent-notice-heading { font-size: var(--font-size-body); margin-top: var(--space-lg); }
.consent-notice { margin: var(--space-sm) 0 0; padding-left: var(--space-lg); }
.consent-notice li { margin-bottom: var(--space-sm); }

/* Pushed to the bottom, never hidden. The font size comes from
   DISCLOSURE_MIN_FONT_PX as an inline style, so nothing here may shrink it. */
.disclosure {
  margin-top: auto;
  padding-top: var(--space-lg);
  color: var(--color-text-muted);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* Who we are and how to complain, under the disclosure on the sign-in screen.

   Set at the same size as the disclosure, from the same constant, and for the
   same reason: a complaint route in smaller type than the risk warning is the
   identical trick played in a different place.

   The links are underlined rather than distinguished by colour alone, so they
   survive a colour-blind reader and a greyscale screen. --color-text-muted is
   held to AA-normal by the design system's contrast tests, so this stays
   readable rather than becoming decorative small print. */
.firm {
  padding-top: var(--space-md);
  color: var(--color-text-muted);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.firm-name { color: var(--color-text); }

/* Wrapped rows rather than links inside a sentence.

   Inline links measured 16.5px tall — a third of the 48px this file opens by
   declaring, on the one route somebody has to complain about us. The people
   using this are on cheap phones with poor digitisers and are exactly the
   people who cannot afford to chase a mis-tap. WCAG exempts links inside a
   sentence from the target size rule; that exemption is not a reason to make a
   complaint route hard to hit.

   Wrapping keeps it compact: two or three fit per row at 375px, so the whole
   footer costs about two rows more than the inline version did. */
.firm-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-md);
}

.firm-links a {
  display: inline-flex;
  align-items: center;
  /* From the constant, so the rule and the number cannot drift. */
  min-height: 48px;
  color: inherit;
  text-decoration: underline;
  /* A phone number broken across two lines is harder to read and to dial. */
  white-space: nowrap;
}

/* Pinned to the bottom on a phone, where a thumb reaches it. The safe-area
   padding is on the body, so this sits above the home indicator rather than
   under it.

   The --tab-bar-height variable is what .screen leaves clear below the
   disclosure. A sticky bar over it clips the last line, and a disclosure you
   cannot finish reading is not "set to be read" — the one thing the minimum
   font size exists to guarantee. Found by looking at the screen, not by a test.

   (No backticks in this comment: the whole stylesheet is a template literal,
   and one would end it.) */
.tabs {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-xs) var(--space-sm);
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}
.tab .ic { display: block; font-size: 15px; line-height: 1; margin-bottom: var(--space-xxs); }

.tab {
  flex: 1;
  background: none;
  border: none;
  color: var(--color-text-muted);
  font-weight: var(--font-weight-medium);
  border-radius: var(--radius-md);
  /* The current tab is a span, the others are buttons. Sized here so the
     three line up whatever element each one is. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 var(--space-sm);
  font-size: var(--font-size-micro);
  color: var(--color-text-faint);
}

/* Current tab marked by weight and colour, not colour alone. */
.tab[aria-current='page'] {
  color: var(--color-accent-text);
  font-weight: var(--font-weight-semibold);
}

/* ---- The three-tab app's components, docs/design/three-tab-app.html ----
   Every value is the design system's token; the prototype's hex values were
   lifted from these in the first place. No shadows: they need an alpha colour
   the contrast suite cannot see, and the ground is dark enough that a hairline
   border does the same job. */

.topbar { display: flex; justify-content: space-between; align-items: center; gap: var(--space-sm); }
.topbar h1.greet { font-size: var(--font-size-title); font-weight: var(--font-weight-bold); letter-spacing: var(--letter-spacing-title); margin: 0; }
.topbar .signout { background: none; border: 0; color: var(--color-accent-text); font-size: var(--font-size-micro); font-weight: var(--font-weight-semibold); padding: 0 var(--space-xs); min-height: 44px; text-decoration: none; }
.sub { color: var(--color-text-faint); font-size: var(--font-size-caption); margin: calc(-1 * var(--space-sm)) 0 0; }

.card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: var(--space-lg); display: flex; flex-direction: column; gap: var(--space-xs); }
.card > h2 { font-size: var(--font-size-body); margin-bottom: var(--space-xs); }
.label { font-size: var(--font-size-micro); text-transform: uppercase; letter-spacing: var(--letter-spacing-label); color: var(--color-text-faint); font-weight: var(--font-weight-semibold); }

.hero-val { font-size: var(--font-size-hero); letter-spacing: var(--letter-spacing-display); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; font-feature-settings: var(--font-feature-tabular); line-height: 1.05; margin: var(--space-xxs) 0 0; }
.delta { font-size: var(--font-size-caption); margin-top: var(--space-xs); font-variant-numeric: tabular-nums; }
.delta--more { color: var(--color-positive); }
.delta--less { color: var(--color-negative); }
.delta--same { color: var(--color-text-muted); }
.asof { font-size: var(--font-size-micro); color: var(--color-text-faint); margin-top: var(--space-sm); }

.bars { margin-top: var(--space-md); display: flex; flex-direction: column; gap: var(--space-sm); }
.bar { display: flex; align-items: center; gap: var(--space-sm); font-size: var(--font-size-micro); color: var(--color-text-faint); }
.bar__name { flex: 0 0 54px; text-transform: uppercase; letter-spacing: var(--letter-spacing-label); font-weight: var(--font-weight-semibold); }
.bar__track { flex: 1; height: 8px; border-radius: var(--radius-pill); background: var(--color-surface-raised); overflow: hidden; }
.bar__fill { display: block; height: 100%; border-radius: var(--radius-pill); }
.bar__fill--in { background: var(--color-border-strong); }
.bar__fill--up { background: var(--color-accent); }
.bar__fill--down { background: var(--color-negative); }
.bar__value { color: var(--color-text); font-variant-numeric: tabular-nums; flex: 0 0 auto; font-size: var(--font-size-caption); }

.today { display: flex; align-items: center; gap: var(--space-sm); background: var(--color-surface-raised); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-md) var(--space-md); }
.today .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--color-positive); flex: 0 0 auto; }
.today--pending .dot { background: var(--color-caution); }
.today--failed .dot { background: var(--color-negative); }
.today--next .dot { background: var(--color-accent); }
.today p { margin: 0; font-size: var(--font-size-caption); }
.today small { display: block; color: var(--color-text-faint); font-size: var(--font-size-micro); }

.holding { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-sm); padding: var(--space-md) 0; border-bottom: 1px solid var(--color-border); }
.holding:last-child { border-bottom: 0; padding-bottom: var(--space-xxs); }
.holding .nm { font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); line-height: var(--line-height-snug); }
.holding .mt { font-size: var(--font-size-micro); color: var(--color-text-faint); margin-top: var(--space-xxs); }
.holding .amt { text-align: right; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.holding .amt b { display: block; font-size: var(--font-size-caption); }
.holding .amt span { font-size: var(--font-size-micro); color: var(--color-positive); }

.pending { background: var(--color-surface-raised); border: 1px dashed var(--color-border-strong); border-radius: var(--radius-lg); padding: var(--space-lg); }
.pending p { margin: 0; font-size: var(--font-size-caption); }
.pending small { display: block; color: var(--color-text-faint); font-size: var(--font-size-micro); margin-top: var(--space-xs); }

/* Who the current step is waiting on. One line, on one step. */
.holds { display: block; margin-top: 4px; font-size: var(--font-size-micro); font-weight: var(--font-weight-semibold); color: var(--color-text-faint); letter-spacing: 0.02em; }
.holds--you { color: var(--color-accent); }

/*
 * A statement line puts the amount first and the day on the right: a list of
 * money is scanned down the amounts and across to the date, never the other
 * way. Tabular figures so the rupees line up as a column rather than jittering
 * with the digits.
 */
/*
 * The AMFI line sits under the name and ARN, in the same quiet weight. It is
 * an identity, not a disclaimer: legible, never emphasised, never smaller than
 * the rest of the footer.
 */
/*
 * The identity every screen carries: name, ARN, AMFI registration.
 *
 * Quiet, never hidden. It wraps to as many lines as it needs on a narrow
 * phone, and each of the three parts stays whole — an ARN broken across a line
 * reads as decoration rather than as a registration number.
 */
.identity {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  margin-top: var(--space-lg);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-faint);
}

.arow--stat { align-items: baseline; }
.arow--stat b { font-variant-numeric: tabular-nums; }
.statday {
  color: var(--color-text-faint);
  font-size: var(--font-size-caption);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-left: var(--space-sm);
}

.pill { display: inline-block; font-size: 10px; padding: 2px 7px; border-radius: var(--radius-pill); font-weight: var(--font-weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; border: 1px solid var(--color-border); color: var(--color-text-muted); background: var(--color-surface-raised); vertical-align: middle; }
.pill--ok { color: var(--color-positive); border-color: var(--color-positive); }
.pill--wait { color: var(--color-caution); border-color: var(--color-caution); }
.pill--off { color: var(--color-text-faint); }

.mrows { list-style: none; margin: 0; padding: 0; }
.mrow { padding: var(--space-md) 0; border-bottom: 1px solid var(--color-border); }
.mrow:last-child { border-bottom: 0; padding-bottom: var(--space-xxs); }

/* The fund picker: house chips, then a scrolling list of radio rows. The
   rows are labels around radios so the choice is form state; the checked
   row is drawn like a selected card rather than showing the dot. */
.chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin: var(--space-sm) 0; }
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip span { display: inline-block; font-size: var(--font-size-caption); padding: 4px 12px; border-radius: var(--radius-pill); border: 1px solid var(--color-border); color: var(--color-text-muted); background: var(--color-surface-raised); cursor: pointer; }
.chip input:checked + span { color: var(--color-accent); border-color: var(--color-accent); font-weight: var(--font-weight-semibold); }
.chip input:focus-visible + span { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.frows { max-height: 320px; overflow-y: auto; border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface-raised); margin-bottom: var(--space-sm); }
.frow { display: block; padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--color-border); cursor: pointer; }
.frow:last-of-type { border-bottom: 0; }
.frow input { position: absolute; opacity: 0; width: 0; height: 0; }
.frow-name { display: block; font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); line-height: var(--line-height-snug); }
.frow-meta { display: block; font-size: var(--font-size-micro); color: var(--color-text-faint); margin-top: 2px; }
.frow:has(input:checked) { border-left: 3px solid var(--color-accent); background: var(--color-surface); }
.frow:has(input:checked) .frow-name { color: var(--color-accent); }
.frow:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.frows #fund-count { padding: var(--space-sm) var(--space-md); margin: 0; }
.mrow .top { display: flex; justify-content: space-between; gap: var(--space-sm); align-items: flex-start; }
.mrow .nm { font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); line-height: var(--line-height-snug); }
.mrow .mt { font-size: var(--font-size-micro); color: var(--color-text-faint); margin-top: var(--space-xxs); }
.mrow .amt { font-variant-numeric: tabular-nums; font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); flex: 0 0 auto; text-align: right; }
.acts { display: flex; gap: var(--space-xs); margin-top: var(--space-sm); flex-wrap: wrap; align-items: center; }
.acts button { background: transparent; border: 1px solid var(--color-border-strong); color: var(--color-text); border-radius: var(--radius-sm); padding: 0 var(--space-md); font-size: var(--font-size-micro); font-weight: var(--font-weight-semibold); min-height: 44px; }
.acts button.danger { color: var(--color-negative); border-color: var(--color-negative); }
.acts .why { font-size: var(--font-size-micro); color: var(--color-text-faint); }

.arows { list-style: none; margin: 0; padding: 0; }
.arow { display: flex; justify-content: space-between; align-items: center; gap: var(--space-sm); padding: var(--space-md) 0; border-bottom: 1px solid var(--color-border); width: 100%; background: transparent; border-left: 0; border-right: 0; border-top: 0; font: inherit; color: inherit; text-align: left; border-radius: 0; }
.arow:last-child, li:last-child > .arow { border-bottom: 0; }
.arow b { font-size: var(--font-size-caption); display: block; }
.arow small { display: block; color: var(--color-text-faint); font-size: var(--font-size-micro); margin-top: 1px; }
.arow .chev { color: var(--color-text-faint); }
.arow .val { text-align: right; font-size: var(--font-size-caption); font-variant-numeric: tabular-nums; }

.rev { display: flex; justify-content: space-between; gap: var(--space-sm); padding: var(--space-sm) 0; border-bottom: 1px solid var(--color-border); font-size: var(--font-size-caption); }
.rev:last-of-type { border-bottom: 0; }
.rev span { color: var(--color-text-faint); }
.rev b { font-variant-numeric: tabular-nums; text-align: right; }

.note { background: var(--color-surface-raised); border: 1px solid var(--color-border); border-left: 2px solid var(--color-accent); border-radius: 0 var(--radius-md) var(--radius-md) 0; padding: var(--space-md) var(--space-md); }
.note--caution { border-left-color: var(--color-caution); }
.note p { margin: 0; font-size: var(--font-size-micro); color: var(--color-text-muted); }

.steps { margin: 0; padding: 0; list-style: none; }
.steps li { display: flex; gap: var(--space-sm); padding: var(--space-sm) 0; border-bottom: 1px solid var(--color-border); font-size: var(--font-size-caption); align-items: flex-start; }
.steps li:last-child { border-bottom: 0; }
.steps .k { width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto; display: grid; place-items: center; font-size: 11px; font-weight: var(--font-weight-bold); border: 1px solid var(--color-border-strong); color: var(--color-text-faint); }
.steps .k--done { background: var(--color-positive); border-color: var(--color-positive); color: var(--color-on-accent); }
.steps .k--now { border-color: var(--color-accent); color: var(--color-accent-text); }
.steps small { display: block; color: var(--color-text-faint); font-size: var(--font-size-micro); }

.err { background: var(--color-surface-raised); border: 1px solid var(--color-negative); border-radius: var(--radius-lg); padding: var(--space-md) var(--space-lg); }
.err p { margin: 0; font-size: var(--font-size-caption); }
.err small { display: block; color: var(--color-text-faint); font-size: var(--font-size-micro); margin-top: var(--space-xs); }

.ghost { width: 100%; background: transparent; color: var(--color-accent-text); border: 1px solid var(--color-border-strong); border-radius: var(--radius-md); padding: 0 var(--space-md); font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); min-height: 48px; }
.primary--danger { background: var(--color-negative); color: var(--color-on-accent); }
.crumb { background: none; border: 0; color: var(--color-accent-text); font-size: var(--font-size-caption); font-weight: var(--font-weight-semibold); padding: 0; min-height: 44px; text-align: left; align-self: flex-start; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

