/* Educircle Website V2 — authenticated student shell
   ==================================================
   The chrome shared by every signed-in student page: the fixed-header offset, the
   page hero, the context-aware action rail, the status summary card, and the scroll
   motion layer.

   All of it is built from the tokens in tokens.css. Nothing here introduces a colour,
   a radius or a duration of its own — dashboard.css holds the dashboard's own pieces
   and this file must not duplicate them.

   THE BUG THIS FIXES FIRST
   ------------------------
   `.site-header` is position:fixed and `--header-h` tall. `.v2-disc-hero` reserved
   that space; a bare `.v2-disc` did not. Every authenticated page — dashboard,
   appointments, requests, applications, plan matches/readiness — therefore began
   underneath the header, which is exactly the cramped, overlapping top the owner saw
   on mobile. The rule below fixes all of them at once, and because it is scoped to
   :first-child it cannot double up on pages that already open with a hero. */

/* ── The page shell: ONE content grid for every student page ─────────────────

   THE SECOND BUG THIS FIXES (Phase 14A.4)
   ---------------------------------------
   `.v2-disc` sets `padding-block` only — no max-width, no inline padding. The site's
   content grid actually comes from `.container`, which the site header uses as
   `.container container--wide`. Public discovery pages nest a `.container` inside
   `.v2-disc`; the authenticated pages never did.

   On desktop that meant the header logo sat inside a 1320px centred column while the
   page title, cards and action rail started at x=0 and ran the full viewport width. At
   1920px it reads as a broken page — exactly what the owner's QA screenshots show on
   /requests, /appointments and /applications.

   `.stu-shell` is that missing column, and it mirrors `.container container--wide`
   exactly — same max-width token, same gutter token — so content lines up WITH the
   header logo and the "Create My Australia Plan" CTA rather than merely being centred
   too. It goes on the `.v2-disc` element itself: one class per page, and it cannot
   double-gutter the discovery pages that already nest their own `.container`. */
.stu-shell {
  width: 100%;
  max-width: var(--container-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ── Clearance for the fixed bottom-right widgets ────────────────────────────

   `.v2-savedpill` (right:18px bottom:20px) and the Sage launcher `.sagew`
   (right/bottom 1.25rem) are both fixed to the bottom-right. Two consequences the
   owner's screenshots caught:

   1. They overlapped each other — the saved pill sits at a lower z-index, so the Sage
      button covered it.
   2. Together they covered the last row of page content, which on a short module page
      is the action rail. In the /appointments shot the "Student ambassadors" card is
      hidden behind them.

   Fixed by giving the shell a tail that reserves the widgets' footprint, and by lifting
   the saved pill to sit ABOVE the launcher instead of under it. */
:root {
  /* Launcher footprint: its own height plus its bottom offset. One place to change. */
  --sticky-launcher-h: 56px;
  --sticky-gap: 8px;
}

.v2-savedpill {
  /* Stack above the Sage launcher rather than behind it. */
  bottom: calc(1.25rem + var(--sticky-launcher-h) + var(--sticky-gap));
}

/* The tail. Applied to the shell so every student page reserves the same space, and
   generous enough that both stacked widgets clear the final row of content.

   Kept at every width on purpose. It is tempting to drop it on desktop "because there
   is a gutter now", but the column is 1320px wide and the widgets are pinned ~20px from
   the viewport edge: between roughly 1024px and 1760px the gutter is narrower than the
   saved pill, so they would still land on the last row. Holding one tail everywhere also
   gives Issue F what it asks for — a short module page no longer runs straight into the
   footer. */
.stu-shell {
  padding-bottom: calc(var(--sticky-launcher-h) + var(--sp-7));
}

/* ── Fixed-header offset ──────────────────────────────────────────────────── */

/* Only when the block is the first thing in <main>. A `.v2-disc` that follows a hero
   is mid-page and must keep its normal rhythm. */
#disc-main > .v2-disc:first-child,
#main > .v2-disc:first-child {
  padding-top: calc(var(--header-h) + var(--sp-6));
}

@media (min-width: 768px) {
  #disc-main > .v2-disc:first-child,
  #main > .v2-disc:first-child {
    padding-top: calc(var(--header-h) + var(--sp-7));
  }
}

/* ── Student page hero ────────────────────────────────────────────────────── */

/* A light hero for interior student pages. Deliberately NOT the navy `.v2-disc-hero`:
   that one belongs to public discovery landings, and using it on every interior page
   would make the dashboard's navy journey band stop meaning anything. */
.stu-hero {
  padding-top: calc(var(--header-h) + var(--sp-6));
  padding-bottom: var(--sp-2);
}

@media (min-width: 768px) {
  .stu-hero { padding-top: calc(var(--header-h) + var(--sp-7)); }
}

/* A hero inside an already-offset container must not add the offset twice. */
#disc-main > .v2-disc:first-child .stu-hero,
.stu-hero.stu-hero--flush { padding-top: 0; }

.stu-hero__back {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  /* A 44px tap target grown DOWNWARD and to the right only. An earlier version used a
     negative inline start to centre the padding on the text, which pushed the link 8px
     into the page gutter — harmless for scrolling but it broke alignment with the title
     underneath, and it left almost nothing between the link and the viewport edge at
     360px. Keeping the inline start at zero means the link, the title and the lead all
     share one left edge. */
  min-height: 44px;
  padding-inline-end: 0.5rem;
  padding-block: 0.5rem;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--c-primary);
  border-radius: var(--r-sm);
}

.stu-hero__back:hover { color: var(--c-primary-700); }
.stu-hero__back svg { flex: none; }

.stu-hero__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.stu-hero__title {
  font-size: var(--fs-h2);
  color: var(--c-navy);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  margin-top: var(--sp-2);
  overflow-wrap: anywhere;
}

.stu-hero__lead {
  font-size: var(--fs-body-lg);
  color: var(--c-muted);
  line-height: var(--lh-body);
  margin-top: var(--sp-3);
  max-width: 62ch;
}

/* ── Status summary card ──────────────────────────────────────────────────── */

.stu-summary {
  margin-top: var(--sp-5);
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  background: var(--grad-navy);
  color: var(--c-on-dark);
  display: grid;
  gap: var(--sp-4);
}

@media (min-width: 860px) {
  .stu-summary { grid-template-columns: 1.4fr 1fr; align-items: center; }
}

.stu-summary > * { min-width: 0; }
.stu-summary .eyebrow { color: #6FD0FF; }

.stu-summary__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  color: #fff;
  line-height: var(--lh-snug);
  margin-top: var(--sp-2);
}

.stu-summary__body {
  font-size: var(--fs-small);
  color: var(--c-on-dark-muted);
  line-height: var(--lh-body);
  margin-top: var(--sp-2);
}

.stu-summary__cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.stu-summary__cta .btn { flex: 0 0 auto; }

/* Light variant for a neutral / not-yet-started state. */
.stu-summary--quiet {
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  color: var(--c-ink);
}
.stu-summary--quiet .eyebrow { color: var(--c-primary); }
.stu-summary--quiet .stu-summary__title { color: var(--c-navy); }
.stu-summary--quiet .stu-summary__body { color: var(--c-muted); }

/* ── Action rail ──────────────────────────────────────────────────────────── */

/* The answer to dead-end pages: one primary action already lives in the page, and
   this rail carries the two-to-four sideways moves that make sense HERE. Every page
   passes its own set — it is never the same list everywhere. */
.stu-rail {
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--c-line);
}

.stu-rail__title {
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--ls-eyebrow);
  font-weight: var(--fw-bold);
  color: var(--c-muted);
}

.stu-rail__grid {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  grid-template-columns: 1fr;
}

@media (min-width: 560px) { .stu-rail__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .stu-rail__grid { grid-template-columns: repeat(4, 1fr); } }

.stu-rail__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  /* 44px minimum on the shortest possible content. */
  min-height: 56px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-navy);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  min-width: 0;
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.stu-rail__item svg { flex: none; color: var(--c-primary); }
.stu-rail__item span { min-width: 0; overflow-wrap: anywhere; }

.stu-rail__item:hover,
.stu-rail__item:focus-visible {
  border-color: var(--c-vibrant);
  box-shadow: var(--sh-sm);
  transform: translateY(-2px);
}

/* Pressed state must be felt on touch, where there is no hover. */
.stu-rail__item:active { transform: translateY(0) scale(0.99); }

/* ── Shared primitives: status pills, list rows, card CTA ─────────────────── */

/* These began life in dashboard.css and are used by every signed-in page. Because that
   stylesheet is only loaded on the dashboard, /appointments and /requests rendered
   unstyled pills and bulleted lists until they moved here. The `dash-` prefix is kept
   deliberately: the class names are already in markup and pinned by tests, and renaming
   them would be churn with no behaviour change. */

.dash-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  border-radius: var(--r-pill);
  padding: 0.25rem 0.625rem;
  border: 1px solid transparent;
  /* Status labels are short, so they read best on one line — but never at the cost of
     pushing the page sideways. */
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Status is never carried by colour alone: each pill names its state, and the dot is a
   second, non-colour cue. */
.dash-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.dash-pill--complete  { color: #35651C; background: #EDF6E3; border-color: #CFE5B8; }
.dash-pill--progress  { color: #0B4B87; background: #E7F1FC; border-color: #C3DCF5; }
.dash-pill--waiting   { color: #8A5A00; background: #FFF6E3; border-color: #F0DCAE; }
.dash-pill--neutral   { color: #4B5A6B; background: var(--c-surface-2); border-color: var(--c-line); }
.dash-pill--attention { color: #9A2C2C; background: #FCEDED; border-color: #F1CFCF; }

/* A pill sitting on the navy summary card needs its own contrast. */
.stu-summary:not(.stu-summary--quiet) .dash-pill--neutral {
  color: var(--c-on-dark);
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.2);
}

.dash-list { display: grid; gap: var(--sp-3); margin: 0; padding: 0; list-style: none; }

.dash-list li {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  min-width: 0;
}

.dash-list__title { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--c-navy); line-height: 1.4; overflow-wrap: anywhere; }
.dash-list__meta { font-size: var(--fs-eyebrow); color: var(--c-muted); overflow-wrap: anywhere; }
.dash-list__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }

.dash-card__cta { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--c-primary); }

/* ── Request categories ───────────────────────────────────────────────────── */

.stu-cats {
  display: grid;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 700px) { .stu-cats { grid-template-columns: repeat(2, 1fr); } }

.stu-cat {
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}

.stu-cat__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-bold);
  color: var(--c-navy);
}

.stu-cat__title svg { flex: none; color: var(--c-primary); }
.stu-cat__body { font-size: var(--fs-small); color: var(--c-muted); line-height: var(--lh-body); }
.stu-cat__foot { margin-top: auto; padding-top: var(--sp-3); }

/* ── Empty states ─────────────────────────────────────────────────────────── */

/* A useful empty state, not a dead one: it says what this page is for and offers the
   next real move. */
.stu-empty {
  margin-top: var(--sp-5);
  padding: var(--sp-6) var(--sp-5);
  border: 1px dashed var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface-2);
}

.stu-empty__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  color: var(--c-navy);
}

.stu-empty__body {
  font-size: var(--fs-small);
  color: var(--c-muted);
  line-height: var(--lh-body);
  margin-top: var(--sp-2);
  max-width: 58ch;
}

.stu-empty__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }

/* ── Section rhythm ───────────────────────────────────────────────────────── */

.stu-section { margin-top: var(--sp-7); }

.stu-section__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  color: var(--c-navy);
}

.stu-section__note { font-size: var(--fs-small); color: var(--c-muted); margin-top: var(--sp-2); }

/* ── Breathing room before the footer ─────────────────────────────────────── */

/* Short pages (appointments with nothing booked, requests with nothing raised) used to
   hand straight over to the heavy navy footer. */
#disc-main > .v2-disc:last-child,
.stu-tail { padding-bottom: var(--sp-8); }

/* ── Micro-interactions ───────────────────────────────────────────────────── */

/* The reveal/stagger/progress system lives in motion.css, shared with the auth pages.
   What follows is only the hover and pressed feedback these components own. */

/* Buttons and cards get a small, fast pressed response. */
.dash-card,
.stu-cat {
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.dash-card:hover,
.stu-cat:hover {
  border-color: #CBDCEF;
  box-shadow: var(--sh-sm);
}

.dash-card__cta,
.stu-rail__item,
.stu-hero__back {
  /* A link that moves on tap needs a transform origin that doesn't jitter text. */
  will-change: auto;
}

.dash-card__cta { transition: color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out); }
.dash-card__cta:hover { color: var(--c-primary-700); transform: translateX(2px); }
.dash-card__cta:active { transform: translateX(0); }

.btn { transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out); }
.btn:active { transform: scale(0.985); }

/* ── Reduced motion ───────────────────────────────────────────────────────── */

/* Flattens the micro-interactions this file owns. The reveal system flattens its own in
   motion.css, so each stylesheet is responsible for exactly what it defines. */
@media (prefers-reduced-motion: reduce) {
  .stu-rail__item:hover,
  .stu-rail__item:focus-visible,
  .stu-rail__item:active,
  .dash-card__cta:hover,
  .dash-card__cta:active,
  .btn:active {
    transform: none;
  }

  .dash-card,
  .stu-cat,
  .stu-rail__item,
  .dash-card__cta,
  .btn {
    transition: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   Profile + documents (Phase 14A.4)

   Both pages replace trips into the legacy student portal, so they are styled from the
   same tokens as the rest of the workspace rather than inheriting the old portal's look.

   Every control is at least 44px in its smallest dimension and every text input is 16px,
   below which iOS Safari zooms the page on focus.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Shared form field ────────────────────────────────────────────────────── */

.prof-form,
.doc-form {
  margin-top: var(--sp-6);
}

.prof-group {
  /* A fieldset, so the grouping is announced and not merely drawn. Browsers give
     fieldsets a default border and padding that would fight the card look. */
  border: 0;
  margin: 0 0 var(--sp-6);
  padding: var(--sp-5);
  border: 1px solid var(--c-line, #e4eaf0);
  border-radius: var(--r-lg, 14px);
  background: #fff;
  box-shadow: var(--sh-sm, 0 1px 3px rgba(2, 44, 84, .07));
}

.prof-group__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  /* A legend sits in the border by default; float it out so it reads as a card heading. */
  float: none;
  width: auto;
  margin: 0 0 var(--sp-4);
  padding: 0;
  font-size: 1rem;
  font-weight: 700;
  color: var(--c-navy, #022C54);
}

.prof-group__num {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--c-primary, #004AAD);
  color: #fff;
  font-size: .8125rem;
  font-weight: 700;
  flex: none;
}

/* One column on a phone, two from tablet up. minmax(0,1fr) so a long select cannot
   push the grid wider than its track and cause sideways scroll. */
.prof-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4);
}

@media (min-width: 700px) {
  .prof-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4) var(--sp-5);
  }
}

.prof-field {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.prof-label {
  margin-bottom: var(--sp-2);
  font-size: .8125rem;
  font-weight: 700;
  color: var(--c-navy, #022C54);
}

.prof-req {
  color: #c0392b;
}

.prof-input {
  width: 100%;
  min-height: 48px;
  padding: var(--sp-3);
  font-family: inherit;
  font-size: 1rem;
  color: var(--c-ink, #12212e);
  background: #fff;
  border: 1.5px solid var(--c-line, #e4eaf0);
  border-radius: var(--r-sm, 8px);
  transition: border-color var(--dur-fast, 150ms) var(--ease-out, ease-out),
              box-shadow var(--dur-fast, 150ms) var(--ease-out, ease-out);
}

.prof-input:focus {
  outline: none;
  border-color: var(--c-primary, #004AAD);
  box-shadow: 0 0 0 3px rgba(0, 74, 173, .15);
}

/* Invalid fields carry a border AND an adjacent message — colour alone would be
   invisible to anyone who cannot distinguish it. */
.prof-input.is-error {
  border-color: #c0392b;
}

.prof-error {
  margin-top: var(--sp-2);
  font-size: .75rem;
  font-weight: 600;
  color: #c0392b;
}

.prof-help {
  margin-top: var(--sp-2);
  font-size: .75rem;
  color: var(--c-muted, #62778c);
}

.prof-missing {
  margin: var(--sp-4) 0 0;
  padding-left: 1.1rem;
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--c-muted, #62778c);
}

.prof-actions,
.doc-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
}

.prof-tertiary {
  display: inline-flex;
  align-items: center;
  /* Padding-only 44px target: a negative margin here would break the gutter alignment
     the shell exists to guarantee. */
  min-height: 44px;
  padding-inline: var(--sp-2);
  font-size: .875rem;
  font-weight: 700;
  color: var(--c-primary, #004AAD);
  text-decoration: none;
}
.prof-tertiary:hover { text-decoration: underline; }

.prof-note,
.doc-note {
  margin: var(--sp-4) 0 0;
  max-width: 60ch;
  font-size: .8125rem;
  line-height: 1.65;
  color: var(--c-muted, #62778c);
}

/* ── Documents ────────────────────────────────────────────────────────────── */

.doc-list {
  list-style: none;
  margin: var(--sp-4) 0 var(--sp-5);
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}

.doc-row {
  padding: var(--sp-4);
  border: 1px solid var(--c-line, #e4eaf0);
  border-radius: var(--r-md, 10px);
  background: #fff;
}

.doc-row__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.doc-row__name {
  font-size: .9375rem;
  font-weight: 700;
  color: var(--c-navy, #022C54);
}

.doc-row__key {
  display: inline-block;
  margin-left: var(--sp-2);
  font-size: .6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--c-muted, #62778c);
}

.doc-row__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

/* The file input is styled through its label so it looks like the rest of the UI. The
   input itself stays in the DOM and focusable — it is not display:none, which would
   take it out of the tab order and break keyboard use. */
.doc-pick {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--sp-4);
  border: 1.5px solid var(--c-primary, #004AAD);
  border-radius: var(--r-pill, 999px);
  background: #fff;
  color: var(--c-primary, #004AAD);
  font-size: .8125rem;
  font-weight: 700;
  cursor: pointer;
  overflow: hidden;
}

.doc-pick__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.doc-pick:hover {
  background: rgba(0, 74, 173, .06);
}

.doc-pick:has(.doc-pick__input:focus-visible) {
  outline: 3px solid var(--c-focus, #7aa7e0);
  outline-offset: 2px;
}

.doc-row__view {
  font-size: .8125rem;
  font-weight: 700;
  color: var(--c-primary, #004AAD);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.doc-row__view:hover { text-decoration: underline; }

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .prof-input,
  .doc-pick {
    transition: none;
  }
}

/* ── Progress meter (moved from dashboard.css in Phase 14A.4) ────────────────

   Shared by the dashboard's journey band and the profile page's completeness card.
   It lived in dashboard.css, which the discovery layout does not load, so on the new
   profile page the bar rendered as an invisible element — the same class-scope trap
   that hid .dash-pill and .dash-list before they were moved here. */
.dash-meter { margin-top: var(--sp-5); }

.dash-meter__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
}

.dash-meter__value {
  font-size: var(--fs-h3);
  font-weight: var(--fw-extrabold);
  color: #fff;
  font-variant-numeric: tabular-nums;
}

.dash-meter__label { font-size: var(--fs-small); color: var(--c-on-dark-muted); }

.dash-meter__track {
  margin-top: var(--sp-3);
  height: 10px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14);
  overflow: hidden;
}

.dash-meter__fill {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--c-green) 0%, #8FC45C 100%);
  transition: width var(--dur-slow) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .dash-meter__fill { transition: none; }
}
