/* The front door, and nothing else. Class prefix `ld-`.

   One page fills this: `web/templates/index.html`, the page a stranger sees
   before they have an account. It is the only screen in the application whose
   reader has no task, and the only one whose job is a button rather than
   somebody's work.

   It follows the arrangement `receipts.css`, `scan.css`, `limits.css`,
   `dashboard.css`, `exports.css` and `admin.css` already use, for the reason
   base.html gives where it defines the styles block: a page owns its own
   stylesheet with its own prefix rather than appending to `app.css`. Nothing
   here restyles anything shared. `.hero`, `.steps`, `.card` and the buttons are
   app.css's and stay app.css's; the rules below that touch them do so from a
   `.ld-` scoped selector and say so.

   **No colour is written here as a literal.** Every paint below is a
   `var(--...)` from app.css's palette, which is what makes the page work in a
   light scheme and a dark one that were designed separately rather than derived
   from each other. There is no `prefers-color-scheme` block in this file and
   there must not be one: the variables already swap. `tests/test_front_door.py`
   enforces both halves of that -- and it is also why there is no dark band on
   this page the way there is on the page this layout borrows from: a band
   painted black in the light scheme is a literal, and in the dark scheme it
   would be the one thing on the site that did not get darker.

   --- the shape, and where it comes from ------------------------------------

   One idea per screen. A headline readable from across the room, one sentence,
   one button, and the product turning by itself; then four bands, each a single
   claim under a single icon, on alternating surfaces; then the three steps as
   three tiles, the prices as three tiles, and the button again. Everything is
   centred and generous. That is the whole of what is borrowed from the way a
   phone is sold, and it is borrowed because it is right for the same reason
   there: the reader is deciding, not working, and a page that asks them to
   compare two things at once is asking them to work.

   --- the drawing, and why it is this drawing ------------------------------

   `app.css` opens with the sentence that governs anything drawn in this
   application: the theme is mildly nautical and the word is *mildly*. No
   anchor, no wheel, no compass, no porthole, no rope. The one idea it endorses
   is the sonar return, "because it is already what the product does: it finds
   one thing in a noisy picture". So the pictures are exactly that: a receipt,
   the line that is the total picked out, and a ping coming back off it, shown
   at the three moments that matter. Drawn in the idiom of the twenty-pixel
   icons in `_icons.html`, at hero size.

   The receipt in these drawings is not a photograph, which is why it does not
   use `--paper`: in the dark scheme `--paper` is a dark grey mount for a bright
   photograph, right for a photograph and wrong for a line drawing. The sheet is
   a panel like every other panel on the site: `--panel` filled, `--edge`
   outlined.

   --- the motion, which is the only animation in this application -----------

   Three scenes cross-fade on a thirteen and a half second loop, four and a half
   seconds each, and the captions turn with them on the same clock. Two rules
   come with it. **Nothing is only in the motion**: the captions are
   `aria-hidden` and the steps below say the same three things in text. **It
   stops for anybody who asks**: the `prefers-reduced-motion` block at the end
   turns every animation here off and leaves the middle scene standing. */

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

   Stacked and centred at every width: the headline, the sentence, the button,
   and then the product. On a phone that is the only order that keeps the button
   above the fold; on a desktop it is the order the page this borrows from uses,
   and for the same reason -- the product is the picture, and it gets the whole
   width rather than a column. */
.ld-hero {
  padding: 34px 0 8px;
  text-align: center;
}

@media (min-width: 700px) {
  .ld-hero { padding: 54px 0 12px; }
}

/* Larger than app.css's `h1` clamp and tighter, because this is the one
   headline on the site that is read at arm's length rather than while holding a
   receipt. 15ch is the measure that breaks "Receipts, done from your phone."
   after "from" -- two lines at every width, three at 12ch on a desktop. The
   selector beats `.hero h1`'s `max-width: 20ch` on specificity. */
.ld-hero .ld-title {
  font-size: clamp(36px, 7vw, 64px);
  line-height: 1.05;
  letter-spacing: -0.022em;
  max-width: 15ch;
  margin: 0 auto 16px;
}

.ld-hero .ld-lead {
  font-size: clamp(18px, 2.3vw, 22px);
  max-width: 38ch;
  margin: 0 auto 24px;
}

.ld-actions { justify-content: center; }

/* The buttons the page exists for: larger and round-ended, because at this
   size a sharp corner reads as a form control and a pill reads as a thing to
   press. `.button.ld-cta-button` ties with `.button.primary` on specificity and
   sets nothing it sets, so the accent still paints the primary one. */
.button.ld-cta-button {
  padding: 12px 24px;
  font-size: 17px;
  border-radius: 999px;
}

.ld-aside {
  margin: 12px 0 0;
  text-align: center;
}

/* --- the stage: the product, turning ---------------------------------------

   Bigger than the side-by-side version allowed, because it is no longer beside
   anything: 300px is the width of a card on a phone and a third of the measure
   on a desktop, and the drawing's own aspect keeps it half again as tall.
   `height: auto` beside a set `width` is what keeps an SVG at its own aspect
   ratio; without it a grid cell stretches it and the receipt comes out fat. */
.ld-stage {
  margin: 30px auto 0;
  max-width: 300px;
}

.ld-art {
  display: block;
  width: 100%;
  height: auto;
}

/* --- the three scenes, and the clock they share ---------------------------

   13.5s, three scenes, 4.5s each. A third of the loop is 33.33%, so each scene
   fades in over the first tenth of its share and holds. The three are the same
   keyframes with a delay each, which is what keeps them in step: one number to
   change rather than three.

   **The fade-out runs past the third, and that is the whole of the cross-fade.**
   The first version held to 30% and was gone by 33%, which reads as correct
   arithmetic and is not: a scene had finished before the next one's delay
   elapsed, so the hero was *empty* for 0.45s three times a loop -- a tenth of
   the time, on the one picture the page is selling. Found by sampling the
   computed opacity of all three scenes in a browser and getting nought, with
   nine animations running and reduced motion off. Fading out from 33.3% to
   36.3% makes the departing scene overlap the arriving one by exactly the fade,
   which is what a cross-fade is.
   `tests/test_front_door.py::test_the_hero_is_never_blank` does that sampling
   as arithmetic, so the next person to change these numbers is told. */
@keyframes ld-turn {
  0% { opacity: 0; }
  3% { opacity: 1; }
  33.3% { opacity: 1; }
  36.3% { opacity: 0; }
  100% { opacity: 0; }
}

/* `backwards` is load-bearing and was missing in the first version, which is
   worth writing down because the symptom did not look like a fill mode. An
   `animation-delay` does not hold an element at its first keyframe while it
   waits: until the animation starts, the element shows whatever it declares --
   so the reading scene, which declares `opacity: 1` for the reduced-motion case
   below, was drawn on top of the photograph for the first four and a half
   seconds of every page load. `backwards` takes the 0% value during the delay,
   and the static opacity then applies only when there is no animation at all,
   which is exactly the case it exists for. */
.ld-scene {
  opacity: 0;
  animation: ld-turn 13.5s linear infinite backwards;
}

/* The still frame: the scene that stands when nothing animates, and the one
   the reduced-motion block keeps. The reading is the emblem of the product. */
.ld-scene-read { opacity: 1; }

.ld-scene-photo { animation-delay: 0s; }
.ld-scene-read { animation-delay: 4.5s; }
.ld-scene-books { animation-delay: 9s; }

/* The captions, on the same clock and the same keyframes, stacked on one line
   so the turn is a fade rather than a jump. Absolute inside a box with a
   reserved height: three captions of different lengths in normal flow would
   change the height of this box four times a loop, and everything below it
   would move. */
.ld-captions {
  position: relative;
  height: 3.2em;
  margin: 14px 0 0;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
  color: var(--muted);
}

.ld-caption {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  opacity: 0;
  animation: ld-turn 13.5s linear infinite backwards;
}

.ld-caption-read { opacity: 1; }

.ld-caption-photo { animation-delay: 0s; }
.ld-caption-read { animation-delay: 4.5s; }
.ld-caption-books { animation-delay: 9s; }

/* --- what the drawings are painted with -----------------------------------

   The split is by what a thing *is* rather than by what colour it should come
   out: that is the only arrangement in which the dark scheme is a second design
   rather than an inversion. */
.ld-sheet {
  fill: var(--panel);
  stroke: var(--edge);
}

/* The same sheet seen through the camera, and the phone around it. Unfilled:
   inside the frame it sits on the phone's own panel, and a second fill would
   read as a sheet floating above the screen rather than one looked at through
   it. */
.ld-sheet-lite { stroke: var(--edge); }

.ld-frame {
  fill: var(--panel);
  stroke: var(--edge);
}

/* The card the books arrive on: one panel, the same as every other. */
.ld-card {
  fill: var(--panel);
  stroke: var(--edge);
}

/* What is printed: the merchant, the items, the dates. `--muted` is the quiet
   text colour and this is quiet text, deliberately not legible as anything. */
.ld-print { stroke: var(--muted); }

/* The rule above a total, and the one hairline in each picture. */
.ld-rule { stroke: var(--line); }

/* Everything the product found, in the colour of finding. `app.css` says it in
   the palette's own paragraph: "the accent is the colour of the thing found".
   The total, the box around it, the corner marks the camera put on the receipt,
   the shutter, and the ticks beside the filed rows. */
.ld-total { stroke: var(--accent); }
.ld-return { stroke: var(--accent); }
.ld-crop { stroke: var(--accent); }
.ld-shutter { stroke: var(--accent); }
.ld-tick { stroke: var(--accent); }

/* The return itself: three arcs coming back off the line that was found,
   travelling outward while their scene is up -- one keyframe set, a fifth of a
   second between them. The static opacities are for the reduced-motion block
   and for anything that does not animate. The inner arc carries the meaning and
   is the accent at full strength; the outer two are decorative geometry. */
@keyframes ld-ping {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}

.ld-sweep-near {
  stroke: var(--accent);
  animation: ld-ping 2.4s ease-out infinite;
}

.ld-sweep-mid {
  stroke: var(--accent);
  opacity: .68;
  animation: ld-ping 2.4s ease-out .18s infinite;
}

.ld-sweep-far {
  stroke: var(--accent);
  opacity: .42;
  animation: ld-ping 2.4s ease-out .36s infinite;
}

/* --- the four bands -------------------------------------------------------

   Edge to edge on a phone and large rounded panels on a desktop, and the two
   are one rule. `main` is the whole width of a phone with 20px of side padding,
   so a band with -20px side margins touches both edges there; above 700px the
   margins go back to zero and the band becomes a panel inside the measure, with
   the radius a panel that size wants.

   **Not the `calc(50% - 50vw)` breakout**, which was the first version and
   measured 8px wider than the viewport: `100vw` counts the scrollbar and the
   page does not, `body`'s `overflow-x: hidden` is not honoured by iOS Safari,
   and a front door that wobbles sideways under a thumb is the one thing this
   page must not do on the device it is for. Nothing here depends on the
   viewport's width, so nothing here can exceed it.

   Alternating surfaces rather than alternating light and dark, for the reason
   the header gives: a black band is a literal. `--panel` against `--bg` is the
   same contrast every card on the site has with the field it stands on, in both
   schemes. */
.ld-band {
  margin: 0 -20px;
  padding: 58px 20px;
  text-align: center;
}

@media (min-width: 700px) {
  .ld-band {
    margin: 18px 0;
    padding: 84px 28px;
    border-radius: 22px;
  }
}

.ld-band-alt { background: var(--panel); }

.ld-band-inner {
  max-width: 600px;
  margin: 0 auto;
}

/* The icon above each claim, at a size a thumb could press: on a phone these
   bands are read one per screen and the icon is the first thing in each. */
.ld-band .icon {
  width: 2.6em;
  height: 2.6em;
  color: var(--accent);
  margin: 0 auto 12px;
  display: block;
}

.ld-band h2,
.ld-section-title,
.ld-close h2 {
  font-size: clamp(28px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}

.ld-band p,
.ld-close p {
  font-size: clamp(17px, 2vw, 20px);
  color: var(--muted);
  max-width: 46ch;
  margin: 0 auto;
}

/* The five ways a month can leave, as pills. A list of nouns is the whole
   answer to "what can I export", and reading it as a sentence would be slower
   than reading it as a row. */
.ld-formats {
  list-style: none;
  padding: 0;
  margin: 22px 0 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.ld-formats li {
  background: var(--panel-2);
  color: var(--ink);
  border-radius: 999px;
  padding: 7px 15px;
  font-size: 15px;
  font-weight: 600;
}

/* --- the three steps ------------------------------------------------------

   Three tiles rather than three lines, and the icons are the three the person
   will meet on the real screens -- `scan` on the shutter, `review` on the queue,
   `ok` on the band that says a receipt is filed. The element stays an `<ol>` so
   the sequence is still in the document for anything that reads it rather than
   looks at it; the numbers go and the icons take their place.

   Both `ol` selectors tie with app.css's on specificity and win on order, which
   is the intended relationship: app.css still owns the block and this file
   adjusts it. */
.ld-steps {
  margin: 52px 0 12px;
  text-align: center;
}

.ld-section-title { text-align: center; }

.ld-steps ol {
  list-style: none;
  padding: 0;
  margin: 26px 0 0;
  max-width: none;
  display: grid;
  gap: 14px;
}

@media (min-width: 700px) {
  .ld-steps ol {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
  }
}

.ld-steps li {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 24px 20px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--muted);
}

.ld-steps li strong { color: var(--ink); }

/* The marker of the tile, where a number would have stood. app.css's icon rule
   says a page wanting a larger one sizes it from its own stylesheet. */
.ld-steps .icon {
  width: 2.2em;
  height: 2.2em;
  color: var(--accent);
}

/* --- the prices -----------------------------------------------------------

   Three tiles: what is free, what it costs after that, and what can be added.
   The middle one is the one most people will pay, so it carries the accent on
   its edge -- a hairline, not a fill, because a filled tile reads as selected
   and nothing here is a form. */
.ld-pricing {
  margin: 56px 0 8px;
  text-align: center;
}

.ld-tiers {
  display: grid;
  gap: 14px;
  margin: 26px 0 0;
}

@media (min-width: 640px) {
  .ld-tiers {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
    align-items: stretch;
  }
}
@media (min-width: 1000px) {
  .ld-tiers-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.ld-pricing > .ld-addons { margin-top: 18px; }

.ld-tier {
  margin: 0;
  padding: 26px 22px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ld-tier-main { border-color: var(--accent); }

.ld-tier-name {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.ld-tier-price {
  margin: 4px 0;
  font-size: clamp(34px, 5vw, 48px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
}

.ld-tier-price span {
  display: block;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
  margin-top: 8px;
}

.ld-tier-note {
  margin: 0;
  color: var(--muted);
}

/* The add-ons, left-aligned inside a centred tile: two items with a name, a
   reason and a price each read as a list, and a centred list of that shape reads
   as a poem. */
.ld-addons {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  text-align: left;
  display: grid;
  gap: 14px;
  color: var(--muted);
}

.ld-addons strong { color: var(--ink); }

.ld-addons span {
  display: block;
  margin-top: 3px;
  font-weight: 700;
  color: var(--accent);
}

/* --- the button, again ----------------------------------------------------

   Centred, because it is one thing to press and there is nothing to align to. */
.ld-close {
  text-align: center;
  padding: 52px 0 28px;
}

.ld-close p { margin-bottom: 22px; }

/* --- motion off ----------------------------------------------------------

   Everything above stops, and what is left is one complete picture with one
   caption under it: the reading, which is the emblem of the product. A person
   who has asked their operating system for less motion has asked every page
   they open. `tests/test_front_door.py` asserts that every animation declared
   in this file is named here, so an animation added later cannot quietly skip
   it. */
@media (prefers-reduced-motion: reduce) {
  .ld-scene,
  .ld-caption,
  .ld-sweep-near,
  .ld-sweep-mid,
  .ld-sweep-far {
    animation: none;
  }

  .ld-scene-photo,
  .ld-scene-books,
  .ld-caption-photo,
  .ld-caption-books {
    opacity: 0;
  }

  .ld-scene-read,
  .ld-caption-read {
    opacity: 1;
  }
}
