/* Craft pass.

   Four principles, each applied only where a measurement said it was missing:
   continuity of shape, material honesty, real physics, invisible detail.
   Nothing here changes a layout; it changes how solid the app feels. */

/* ---------- invisible detail: a small control can still be easy to hit ----------

   Two controls on Home were 16 and 17 pixels tall: the link to the full
   roadmap and the link into the daily brief. Both are plain text links, and
   making them physically bigger would turn them into buttons and pull focus
   from the primary action next to them. This grows the touch area to 44pt
   around the centre of the control without moving a single pixel of layout.

   Deliberately NOT applied to tightly packed rows. Where controls sit shoulder
   to shoulder, overlapping hit areas send a tap to the wrong control, which is
   worse than a small target. Those are listed in the sprint ledger instead. */
.home-section-heading button,
.home-brief__body button { position: relative; }
.home-section-heading button::after,
.home-brief__body button::after {
  content: "";
  position: absolute;
  left: 50%;
  width: max(100%, 44px);
}

/* The brief link has a quarter of a screen of clear space above and below it,
   so its floor is centred and reaches the full 44pt. */
.home-brief__body button::after {
  top: 50%;
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* The roadmap link does not: the first roadmap row sits 14 pixels below it, and
   that row is the primary action of the whole section. A centred 44pt floor
   would reach exactly that far and start taking taps meant for it, which is a
   worse failure than a small target. So this floor grows upward into the space
   that is actually free and reaches only 4 pixels down. Forty points rather
   than forty-four, and no stolen taps. */
.home-section-heading button::after {
  bottom: -4px;
  height: 40px;
  transform: translateX(-50%);
}

/* ---------- real physics: the control answers the press ----------

   On the easing the app already uses elsewhere, so nothing new is introduced.
   Reduced motion opts out of the movement, not the feedback: every control
   keeps the colour change it already had. */
:where(button, [role="button"], summary):not(:disabled):active {
  transform: scale(.985);
  transition: transform 80ms var(--ease-out, ease);
}
@media (prefers-reduced-motion: reduce) {
  :where(button, [role="button"], summary):not(:disabled):active { transform: none; }
}

/* ---------- continuity of shape ----------

   Where the browser supports it, a rounded rectangle gets a continuous curve
   rather than a quarter circle stuck onto straight edges. Anything already
   fully round is left alone, because the squircle of a circle is not a circle.
   Everything degrades to the existing radius where it is unsupported. */
@supports (corner-shape: squircle) {
  .card,
  .btn,
  .symbol-tile,
  .today-priority,
  .habit-strip,
  .practice-sim,
  .practice-sim__reply,
  .practice-sim__input,
  .prompt-box,
  .practice-portfolio__icon,
  .referral-card__icon { corner-shape: squircle; }
  .chip,
  .habit-strip__dot,
  .practice-sim__badge { corner-shape: round; }
}

/* ---------- material honesty ----------

   A tile inside a card is already a change of material: it carries its own
   tint. The border around it draws a second line describing the same edge, and
   at 48 pixels that seam is most of what the eye reads. The tint carries it
   alone. Inputs keep their edges, because an input has to announce that it
   accepts typing, and a tile that is NOT inside a card keeps its border,
   because there it is the only thing separating it from the page. */
.card .symbol-tile,
.card .practice-portfolio__icon,
.card .referral-card__icon { border-color: transparent; }

/* ---------- the same floor, for the settings and account actions ----------

   The profile screen's action rows are plain text links: replay the tour, open
   the ranking, contact support, delete an account. At a 375 pixel width they
   measured between 17 and 21 pixels tall. Each sits alone in its row inside a
   divided card, with 33 pixels or more of clear space above and below, so a
   full 44pt floor fits without reaching a neighbour.

   The selector is deliberately structural rather than a list of names: an
   action row is a plain p-4 inside a divided card, while the rows that hold a
   control (theme, language, daily goal) are flex rows and are excluded. A row
   that already meets 44pt is unaffected, since the floor never shrinks one. */
.card.divide-y > .p-4:not(.flex) > button,
.card.divide-y > .p-4:not(.flex) > a { position: relative; }
.card.divide-y > .p-4:not(.flex) > button::after,
.card.divide-y > .p-4:not(.flex) > a::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* The plan badge is a button shaped like a chip, 25 pixels tall, with 36 below
   it and nothing above. It keeps its shape and gains the floor. */
button.chip { position: relative; }
button.chip::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* Two pixels short in both directions, and alone in the header. */
.app-header__brand { min-width: 44px; min-height: 44px; }

/* The copy button beside a saved practice proof is icon-only and deliberately
   compact, at 41 by 36. Its row has 24 pixels of horizontal slack and clear
   space well beyond 44 above and below, so the floor fits in both directions
   without the button itself growing. */
.btn.min-h-0.shrink-0 { position: relative; }
.btn.min-h-0.shrink-0::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* Left alone on purpose: the language toggle and the daily-goal numbers are
   already 44pt tall and short only in WIDTH, and their rows have six and
   twelve pixels of slack respectively. Widening them needs a layout change,
   and an overlay would reach straight into the control beside it. The sprint
   ledger records them rather than pretending they are handled. */

/* ---------- what comes after a finished outcome ----------

   Only appears once the active outcome is genuinely finished, so it never
   competes with work still in front of the learner. It reads as an invitation
   rather than an alert: the same card material as everything else, with the
   accent carried by the kicker and the action, not by a coloured edge. */
.next-outcome { margin-top: 12px; padding: 18px; }
.next-outcome__kicker {
  font-size: 10px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand);
}
.next-outcome h2 { margin-top: 8px; font-size: 17px; font-weight: 800; line-height: 1.25; color: var(--ink1); }
.next-outcome__why { margin-top: 8px; font-size: 13px; line-height: 1.55; color: var(--ink3); }
.next-outcome__meta { margin-top: 10px; font-size: 11px; font-weight: 700; color: var(--ink-faint); }
/* The price sits between the commitment and the button, so it is read on the
   way to the tap rather than discovered at a locked lesson afterwards. */
.next-outcome__gate { display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 5px 10px; border-radius: 999px; background: var(--card2); font-size: 11px; font-weight: 800; }
.next-outcome__gate .mahir-icon { width: .82rem; height: .82rem; }

/* The step-back control inside a lesson. It borrows the chevron rather than
   adding a fourteenth glyph to the set, mirrored so it points the way it goes.
   Mirroring an icon is honest here because the shape carries no text and no
   handedness — it is an arrowhead. */
.lesson-back .mahir-icon { transform: scaleX(-1); }

/* The credential, summarised at the top of an outcome. Its own surface comes
   from tone rather than an outline: it sits inside a page that already has
   cards, and another border there would read as a second box rather than as a
   different material. The whole row is the target and clears 44pt on its own
   without a floor being added to it. */
.credential-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  border-radius: 18px;
  background: var(--card2);
  transition: transform 140ms cubic-bezier(.2,.8,.2,1), background 140ms ease;
}
.credential-banner:active { transform: scale(.985); }
.credential-banner__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 12px;
  color: var(--brand);
  background: var(--brand-bg);
}
.credential-banner__mark .mahir-icon { width: 1.05rem; height: 1.05rem; }
.credential-banner__body { display: flex; min-width: 0; flex: 1 1 auto; flex-direction: column; gap: 2px; }
.credential-banner__name {
  overflow: hidden;
  font-size: 13px;
  font-weight: 800;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.credential-banner__state { color: var(--ink3); font-size: 11px; font-weight: 700; }
/* ink3, not ink4: the light ink4 is 2.90 against a white card and carries
   nothing a reader has to see. The chevron is the affordance that says this row
   opens something, so it moves up a step rather than the token moving down. */
.credential-banner__chevron { color: var(--ink3); flex: 0 0 auto; }
.credential-banner__chevron .mahir-icon { width: .9rem; height: .9rem; }
/* Earned reads as earned without shouting: the mark takes the success tone and
   the row keeps its place in the stack. */
.credential-banner.is-earned .credential-banner__mark { color: var(--green-ink); background: var(--green-bg); }
.credential-banner.is-earned .credential-banner__state { color: var(--green-ink); }
.next-outcome__action { width: 100%; margin-top: 14px; min-height: 44px; padding: 12px; font-size: 14px; }
@media (max-width: 350px) { .next-outcome { padding: 14px; } }

/* ---------- the reading column ----------

   The lesson is where a learner spends the fifteen minutes the whole product
   promises, and on a wide screen its text ran to 128 characters a line. The
   comfortable range is roughly 45 to 75: past that the eye loses its place on
   the return sweep, which is felt as the text being tiring rather than as the
   line being long.

   Capping the measure rather than the font keeps every other size untouched.
   The cap only bites where there is too much width to begin with: on a phone
   the stage is already far narrower than this, so the rule is a no-op there
   and needs no breakpoint. */
.lesson-stage-v3 { max-width: 36rem; margin-inline: auto; }

/* ---------- the views the first two passes never reached ----------

   Censusing home, learn and profile missed four screens. Two classes of
   control turned up there, and they want different answers. */

/* Every back link in the app measured 20 pixels tall. Each sits alone at the
   top of its view with 38 pixels or more of clear space, so the floor fits. */
.view-back { position: relative; }
.view-back::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* The roadmap's track rows are the primary navigation of that screen and they
   measured 24 pixels tall, six pixels apart. A floor reaching ten pixels into
   a neighbour six pixels away would hand taps to the wrong track, so these take
   real height instead. The row already centres its contents, so nothing moves
   except the space around them. */
.roadmap-track-row { min-height: 44px; }
