/*
  Shared by every language version of the page.
  
  Extracted from the markup once there was more than one: two copies of three
  hundred lines of CSS is two copies to keep in step, and the one that drifts is
  always the one nobody is looking at.
*/

  /*
    One page, no framework, no fonts fetched, and one inline script — which
    only chooses which store badge to show. It has to open fast on a phone on a
    building's guest wifi, which is the same network the app is judged on.
  */
  :root {
    --ink: #14213d;
    --ink-soft: #47546b;
    --page: #ffffff;
    --wash: #f4f6fb;
    --line: #dfe4ef;
    --brand: #2a4b8d;
    --brand-deep: #223e77;
    --parcel: #e8a857;
    --settled: #2e6b4f;
    --space: 1.5rem;
  }

  @media (prefers-color-scheme: dark) {
    :root {
      --ink: #e8ecf6;
      --ink-soft: #a3aec4;
      --page: #10141f;
      --wash: #171d2c;
      --line: #2a3247;
      --brand: #7fa0e0;
      --settled: #7fd3a8;
    }
  }

  * { box-sizing: border-box; }

  body {
    margin: 0;
    background: var(--page);
    color: var(--ink);
    font: 16px/1.65 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    -webkit-text-size-adjust: 100%;
  }

  .wrap { max-width: 60rem; margin: 0 auto; padding: 0 var(--space); }

  a { color: var(--brand); }

  /* Header */
  header {
    background: linear-gradient(160deg, #35599f, #223e77);
    color: #fff;
    padding: 3.5rem 0 4rem;
  }
  header a { color: #fff; }

  /* The mark on the left, the language switch pushed to the right. */
  .brand { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 2.5rem; }
  .brand .lang { margin-left: auto; }

  /* A link, not a dropdown: there are two languages and naming the other one
     is shorter than asking someone to open a menu to find it. Always written
     in the language it leads to — "Tiếng Việt" is legible to someone who reads
     no English, where "Vietnamese" is not. */
  .lang {
    font-size: 0.9rem;
    padding: 0.4rem 0.8rem;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 0.5rem;
    text-decoration: none;
    white-space: nowrap;
  }
  .lang:hover, .lang:focus-visible { background: rgba(255, 255, 255, 0.14); }
  .brand img { width: 40px; height: 40px; }
  .brand span { font-weight: 600; letter-spacing: 0.01em; }

  h1 {
    font-size: clamp(2rem, 5.5vw, 3.25rem);
    line-height: 1.15;
    margin: 0 0 1rem;
    letter-spacing: -0.02em;
    max-width: 18ch;
  }

  .lede {
    font-size: clamp(1.05rem, 2.4vw, 1.3rem);
    margin: 0 0 2rem;
    max-width: 46ch;
    color: #d5deef;
  }

  .actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

  .btn {
    display: inline-block;
    padding: 0.85rem 1.5rem;
    border-radius: 0.7rem;
    text-decoration: none;
    font-weight: 600;
    border: 1px solid transparent;
  }
  /* On the header, which is always the dark gradient. */
  .btn-primary { background: #fff; color: var(--brand-deep); }
  .btn-ghost { border-color: rgba(255,255,255,0.45); color: #fff; }

  /* On a page section, which is not. The pair above is white-on-dark, and put
     on a `.wash` the ghost was white text on #f4f6fb — not faint, invisible.
     These take their colours from the theme instead of fixing them, so the
     same two rules hold under both colour schemes: --brand and --page are
     redefined together, so whichever way round they are, they contrast. */
  .btn-solid { background: var(--brand); color: var(--page); }
  .btn-outline { border-color: var(--brand); color: var(--brand); }

  /* A device is offered the store it can actually install from, and anything
     unrecognised is offered both. The class comes from the inline script in
     the page head. */
  .on-ios .badge-android, .on-android .badge-ios { display: none; }

  /* Store badges.
     Drawn here rather than fetched: the page makes no external request, and a
     store badge served from a third party would be the one thing on it that
     breaks behind a corporate proxy. Both stores publish official artwork and
     require it unmodified — swap these for the real files before launch. */
  .badges { display: flex; flex-wrap: wrap; gap: 0.75rem; }

  .badge {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
    min-height: 54px;
    padding: 0.5rem 1.15rem;
    background: #000;
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 0.7rem;
    text-decoration: none;
    transition: background 0.15s ease;
  }
  .badge:hover, .badge:focus-visible { background: #1b1b1b; }
  .badge svg { width: 27px; height: 27px; flex: none; }
  .badge small {
    display: block;
    font-size: 0.68rem;
    line-height: 1.25;
    opacity: 0.88;
  }
  .badge strong {
    display: block;
    font-size: 1.12rem;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
  }

  /* The hand-it-across code, beside the store badges in the closing section.

     Its own flex row rather than a third child of `.badges`, which is a row of
     54px items and would have stretched both badges to the height of the code.

     Side by side is stated rather than left to the content. With plain
     wrapping the break was decided by the caption's max-content width, which
     put the code under the badges below about 780px — a width most windows
     are, and one nobody chose. `nowrap` above 42rem, the breakpoint the
     feature grid already uses, makes the line explicit.

     Both rules sit inside the query, and the second one is why. On one line
     the badges must not give ground: they are a flex item like any other and
     were absorbing the squeeze, shrinking just enough that the two of them
     could no longer fit side by side and stacking one store above the other to
     pay for the code. Held rigid *outside* the query they made the opposite
     mistake — below the breakpoint the row has wrapped and the badges have the
     width to themselves, so a rigid pair could not shrink to a 320px phone and
     pushed the whole page sideways instead. The caption does the giving; it
     reflows, and a badge does not.

     Below 39rem or so nothing more can be given — the image is fixed and the
     domain in the caption is one unbreakable word — so the breakpoint sits
     above that with room to spare.

     The image carries its own amber ground and rounded corners, so it needs no
     colours from here and sits on the light wash or the dark one unchanged. */
  .handoff { display: flex; flex-wrap: wrap; gap: 1.25rem 1.75rem; align-items: center; }

  @media (min-width: 42rem) {
    .handoff { flex-wrap: nowrap; }
    .handoff .badges { flex: none; }
  }

  .qr { display: flex; align-items: center; gap: 0.85rem; margin: 0; }
  .qr img { width: 96px; height: 96px; flex: none; }
  .qr figcaption { font-size: 0.9rem; color: var(--ink-soft); max-width: 15rem; }

  /* The web view is the lesser path — it cannot record anything — so it reads
     as an aside under the two things that can. */
  .aside { margin: 1.1rem 0 0; font-size: 0.95rem; color: #c3d0e8; }
  .aside a { color: #fff; }

  /* Sections */
  section { padding: 4rem 0; }
  section.wash { background: var(--wash); }

  h2 {
    font-size: clamp(1.5rem, 3.5vw, 2rem);
    letter-spacing: -0.01em;
    margin: 0 0 0.75rem;
    max-width: 30ch;
  }

  .sub { color: var(--ink-soft); margin: 0 0 2.5rem; max-width: 58ch; }

  /* The problem, as a before/after rather than a claim. */
  .compare { display: grid; gap: 1rem; grid-template-columns: 1fr; }
  @media (min-width: 46rem) { .compare { grid-template-columns: 1fr 1fr; } }

  .card {
    background: var(--page);
    border: 1px solid var(--line);
    border-radius: 0.9rem;
    padding: 1.5rem;
  }
  .card h3 { margin: 0 0 0.5rem; font-size: 1.05rem; }
  .card p { margin: 0; color: var(--ink-soft); }
  .card .tag {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.75rem;
    color: var(--ink-soft);
  }
  .card.now { border-left: 3px solid var(--parcel); }
  .card.after { border-left: 3px solid var(--settled); }

  /* Features */
  .grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
  @media (min-width: 42rem) { .grid { grid-template-columns: 1fr 1fr; } }
  @media (min-width: 64rem) { .grid { grid-template-columns: repeat(3, 1fr); } }

  .feature h3 { margin: 0 0 0.4rem; font-size: 1.05rem; }
  .feature p { margin: 0; color: var(--ink-soft); }
  .feature .mark {
    width: 2.25rem; height: 2.25rem;
    border-radius: 0.6rem;
    background: var(--brand);
    color: #fff;
    display: grid; place-items: center;
    margin-bottom: 0.9rem;
    font-weight: 700;
  }

  /* Process diagrams.

     Two drawings of each: five steps in a row above the breakpoint, stacked
     below it. Switched with `display` rather than a picture element, because
     which source a browser picks is its own business and this had already gone
     wrong once on a phone — a stylesheet media query is resolved against the
     layout viewport by every engine, and the wrong one being merely hidden is
     recoverable in a way that the wrong one being *loaded* is not.

     max-width is never lifted. Whatever ends up displayed, it cannot be wider
     than the column holding it — which is the property that was missing while
     this overflowed to the right. */
  .flow { margin: 0 0 1.25rem; }

  /* No `display` here. `.flow img` is a class *and* an element, which outranks
     a bare `.flow-wide`, so setting display in this rule silently defeated the
     switch below and both drawings were shown at every width. */
  .flow img {
    width: 100%;
    max-width: 100%;
    height: auto;
    border: 1px solid var(--line);
    border-radius: 0.9rem;
  }

  /* Declared so the space is reserved before the file arrives; every stacked
     drawing shares one canvas for exactly that reason. */
  .flow .flow-tall {
    display: block;
    aspect-ratio: 440 / 850;
    /* Capped and centred: stretched across a tablet its labels come out larger
       than the prose around them. */
    max-width: min(100%, 27rem);
    margin-inline: auto;
  }

  .flow .flow-wide { display: none; aspect-ratio: 1240 / 470; }

  @media (min-width: 64rem) {
    .flow .flow-tall { display: none; }
    .flow .flow-wide { display: block; }
  }

  /* Specimen of the exported report. */
  .specimen {
    border: 1px solid var(--line);
    border-radius: 0.9rem;
    overflow: hidden;
    max-width: 44rem;
  }
  .specimen-head {
    padding: 1rem 1.25rem;
    background: var(--wash);
    border-bottom: 1px solid var(--line);
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    justify-content: space-between;
    align-items: baseline;
  }
  .specimen-head span { color: var(--ink-soft); font-size: 0.875rem; }

  /* The table has a min-content width of its own; without a scroll container
     it stretches the document past the viewport on a phone and every line of
     text on the page runs off the right edge. */
  .specimen-scroll { overflow-x: auto; }
  .specimen table {
    width: 100%;
    min-width: 22rem;
    border-collapse: collapse;
    font-size: 0.925rem;
  }
  .specimen th, .specimen td {
    text-align: left;
    padding: 0.6rem 1.25rem;
    border-bottom: 1px solid var(--line);
  }
  .specimen th {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-soft);
  }
  .specimen .n { text-align: right; font-variant-numeric: tabular-nums; }
  /* A date is one thing; broken over two lines it reads as two. */
  .specimen td:first-child, .specimen th:first-child { white-space: nowrap; }
  .specimen tr.struck td { color: var(--ink-soft); text-decoration: line-through; }
  .specimen tr.struck td:first-child { text-decoration: none; }
  .specimen-note {
    margin: 0;
    padding: 1rem 1.25rem;
    color: var(--ink-soft);
    font-size: 0.9rem;
  }

  /* The privacy policy. A page of prose rather than a pitch, so the header
     collapses to a bar — a full gradient hero above a legal document delays
     the only thing the reader came for. */
  header.slim { padding: 1.75rem 0; }
  header.slim .brand { margin-bottom: 0; }

  /* Narrower than `.wrap`, and deliberately: 60rem of unbroken prose is a
     wall, and this is the one page somebody reads top to bottom. */
  .prose { max-width: 44rem; padding: 3.5rem 0 1rem; }
  .prose h1 { max-width: none; font-size: clamp(1.9rem, 4.5vw, 2.6rem); }
  .prose h2 {
    font-size: 1.2rem;
    max-width: none;
    margin: 2.75rem 0 0.6rem;
  }
  .prose p, .prose li { color: var(--ink-soft); max-width: 66ch; }
  .prose ul { padding-left: 1.2rem; }
  .prose li { margin-bottom: 0.4rem; }
  .prose .updated { font-size: 0.9rem; margin-bottom: 2.5rem; }

  /* The one claim worth reading if nothing else is. */
  .prose .headline {
    border-left: 3px solid var(--brand);
    padding-left: 1rem;
    color: var(--ink);
    font-size: 1.05rem;
  }

  footer {
    border-top: 1px solid var(--line);
    padding: 2.5rem 0 3.5rem;
    color: var(--ink-soft);
    font-size: 0.925rem;
  }
  footer .row { display: flex; flex-wrap: wrap; gap: 1.25rem; justify-content: space-between; }
