/* ============================================================
   IPTA Academy — components.css
   The ten base components. Everything on the site is built from
   these; a page stylesheet may lay them out but must not restyle
   them, and must not introduce a colour, size or space value that
   is not a token.

   Load order:  tokens.css  →  components.css  →  page CSS
   <link rel="stylesheet" href="/css/components.css?v=1">

     1  .btn        primary / secondary / ghost
     2  .field      label + input + help + error   (the form atom)
     3  .select
     4  .card
     5  .badge
     6  .tabs
     7  .modal
     8  .toast
     9  .empty
    10  .skeleton

   Three components need ~2KB of JS to be usable: tabs, modal, toast.
   That lives in /js/ui.js. Everything else here is CSS only.
   ============================================================ */


/* ============================================================
   1. BUTTON

   One primary action per screen. Secondary is the alternative
   path; ghost is for destructive or tertiary actions where the
   click should feel deliberate rather than invited.

   Height is 44px (--control-h), 48px for .btn--lg. Both clear the
   44px tap-target floor with no exceptions on mobile.
   ============================================================ */

/* ------------------------------------------------------------
   [hidden] MUST WIN

   The HTML `hidden` attribute is only a UA stylesheet rule —
   `[hidden] { display: none }` at specificity (0,1,0). Any class
   that sets `display` beats it, and .btn sets inline-flex.

   So `button.btn[hidden]` stayed visible. That is how "Apply
   filters" kept showing on /find even though js/find.js had
   correctly hidden it: the attribute was set, the pixel was not.
   The same trap was already worked around twice below, on
   .tabs__panel and .nav__drawer, one element at a time. This
   states it once for everything.
   ------------------------------------------------------------ */
[hidden] { display: none !important; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-h);

  min-height: var(--control-h);
  padding: 0 var(--sp-3);

  font-size: var(--fs-1);
  font-weight: var(--fw-semibold);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;

  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  user-select: none;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}

.btn:focus-visible { box-shadow: var(--ring); outline: none; }

.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* Primary — Jackfruit Gold. White on --gold-700 is 5.58:1. */
.btn--primary {
  background: var(--accent-solid);
  color: var(--on-accent-solid);
  text-decoration: none;
}
.btn--primary:hover { background: var(--accent-solid-hover); color: var(--on-accent-solid); }
.btn--primary:active { background: var(--gold-700); color: var(--white); }

/* Secondary — outlined ink. */
.btn--secondary {
  background: var(--bg-card);
  color: var(--text);
  border-color: var(--border-strong);
  text-decoration: none;
}
.btn--secondary:hover { background: var(--bg-subtle); border-color: var(--grey-500); color: var(--text); }

/* Ghost — text only. */
.btn--ghost {
  background: transparent;
  color: var(--text-link);
  padding-inline: var(--sp-2);
  text-decoration: none;
}
.btn--ghost:hover { background: var(--accent-subtle); color: var(--accent-hover); }

/* On the ink header/footer. Amber on ink is 3.45:1 — legal for a
   button label at 16px semibold (large-text threshold) but we use
   white on amber here anyway, which is 5.02:1. */
.btn--on-dark.btn--secondary {
  background: transparent;
  color: var(--text-inverse);
  border-color: var(--grey-600);
}
.btn--on-dark.btn--secondary:hover { background: var(--forest-soft); color: var(--text-inverse); }
.btn--on-dark:focus-visible { box-shadow: var(--ring-inverse); }

.btn--lg    { min-height: var(--control-h-lg); padding-inline: var(--sp-4); }
.btn--block { display: flex; width: 100%; }

/* Loading. Set aria-busy="true" and the label is replaced by a
   spinner, so the button width does not jump. */
.btn[aria-busy="true"] { color: transparent !important; position: relative; pointer-events: none; }
.btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  width: 1rem; height: 1rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: jf-spin 600ms linear infinite;
}
.btn--primary[aria-busy="true"]::after { border-color: var(--ink); border-top-color: transparent; }
.btn--secondary[aria-busy="true"]::after,
.btn--ghost[aria-busy="true"]::after { border-color: var(--ink); border-top-color: transparent; }

@keyframes jf-spin { to { transform: rotate(360deg); } }


/* ============================================================
   2. FIELD — the form atom.

   Markup, always, with no exceptions:

     <div class="field">
       <label class="field__label" for="phone">Phone number</label>
       <input class="input" id="phone" name="phone" type="tel"
              inputmode="numeric" autocomplete="tel"
              aria-describedby="phone-help">
       <p class="field__help" id="phone-help">We WhatsApp your class link here.</p>
     </div>

   With an error, add aria-invalid and point aria-describedby at
   the error instead:

     <input class="input" id="phone" aria-invalid="true"
            aria-describedby="phone-err">
     <p class="field__error" id="phone-err">Enter an 11-digit number.</p>

   No placeholder-as-label, ever. A placeholder disappears the
   moment someone types, which is exactly when they need it.
   ============================================================ */

.field { display: block; margin-bottom: var(--sp-3); }

.field__label {
  display: block;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  color: var(--text);
}
.field__label .req { color: var(--danger-700); margin-left: 2px; }

.input,
.textarea {
  display: block;
  width: 100%;
  min-height: var(--control-h);
  padding: 0.625rem var(--sp-2);

  font-size: var(--fs-1);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--bg-card);

  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);

  /* iOS zooms the page on focus for any input under 16px.
     --fs-1 is exactly 16px, so this never happens. Do not shrink it. */
  -webkit-appearance: none;
  appearance: none;
}
.textarea { min-height: 7.5rem; resize: vertical; }

.input::placeholder,
.textarea::placeholder { color: var(--text-muted); opacity: 1; }

.input:hover, .textarea:hover { border-color: var(--grey-500); }

.input:focus, .textarea:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px var(--gold-100);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"] { border-color: var(--danger-700); }
.input[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px var(--danger-50); }

.input[disabled], .textarea[disabled] {
  background: var(--bg-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}

.field__help,
.field__error { margin: var(--sp-1) 0 0; font-size: var(--fs-0); line-height: 1.5; }
.field__help  { color: var(--text-muted); }
.field__error { color: var(--danger-700); font-weight: var(--fw-semibold); }

/* Checkbox / radio. 20px box inside a 44px tap row. */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-1);
  min-height: var(--control-h);
  padding: var(--sp-1) 0;
  cursor: pointer;
}
.check input[type="checkbox"],
.check input[type="radio"] {
  flex: none;
  width: 1.25rem; height: 1.25rem;
  margin: 0.125rem 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.check__text { font-size: var(--fs-0); line-height: 1.5; color: var(--text); }


/* ============================================================
   3. SELECT
   Native element. A custom dropdown costs JS, breaks on Android
   keyboards, and buys nothing a student can see.
   ============================================================ */

.select {
  display: block;
  width: 100%;
  min-height: var(--control-h);
  padding: 0.625rem var(--sp-5) 0.625rem var(--sp-2);

  font-size: var(--fs-1);
  color: var(--text);
  background-color: var(--bg-card);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%23656F7E' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-2) center;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.select:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px var(--gold-100);
}
.select[aria-invalid="true"] { border-color: var(--danger-700); }


/* ============================================================
   4. CARD
   The course card, the cohort card, the instructor card, the
   dashboard panel. One component.
   ============================================================ */

.card {
  display: block;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-3);
}

.card--flush  { padding: 0; overflow: hidden; }
.card--sunken { background: var(--bg-subtle); border-color: transparent; }
.card--accent { border-color: var(--accent-border); background: var(--accent-subtle);
                border-left: 3px solid var(--accent-solid); }

/* Clickable card. The whole card is the target; the heading link
   is the accessible name, and ::after stretches it over the card
   so screen readers get one link, not five. */
.card--link { position: relative; transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.card--link:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.card--link:focus-within { box-shadow: var(--ring); }
.card__stretch::after { content: ""; position: absolute; inset: 0; }
.card__stretch { text-decoration: none; color: inherit; }
.card__stretch:hover { text-decoration: underline; text-underline-offset: 2px; }

.card__media { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; background: var(--bg-sunken); }
.card__body  { padding: var(--sp-3); }
.card__title { font-size: var(--fs-2); font-weight: var(--fw-semibold); line-height: var(--lh-tight); margin: 0 0 var(--sp-1); }
.card__meta  { font-size: var(--fs-0); color: var(--text-muted); margin: 0; }
.card__foot  { margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--border);
               display: flex; align-items: center; justify-content: space-between;
               gap: var(--sp-1); flex-wrap: wrap; }

/* Price. Always tabular, always the largest thing in the footer, and
   never allowed to wrap mid-figure — "Tk 12,000" breaking across two
   lines is the single ugliest thing a card can do. The struck-out
   list price sits on its own line above it. */
.card__price {
  font-size: var(--fs-2);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-tight);
  white-space: nowrap;
}
.card__price del {
  display: block;
  color: var(--text-muted);
  font-weight: var(--fw-regular);
  font-size: var(--fs-0);
}


/* ============================================================
   5. BADGE
   Seats left, batch status, verified score, exam board.

   .badge--urgent is the ONLY warm-red-adjacent thing on the site
   and it is reserved for genuine scarcity — "3 seats left" when
   there really are three. Using it for anything else is how a
   premium site turns into a coaching-centre banner.
   ============================================================ */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-h);
  padding: 0.1875rem var(--sp-1);

  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  line-height: 1.4;
  white-space: nowrap;

  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--grey-600);
}

.badge--accent   { background: var(--accent-subtle); color: var(--gold-800); border-color: var(--accent-border); }
.badge--success  { background: var(--success-50);    color: var(--success-700); }
.badge--urgent   { background: var(--danger-50);     color: var(--danger-700); }
.badge--ink      { background: var(--ink);           color: var(--text-inverse); }
.badge--outline  { background: transparent;          color: var(--text-muted); border-color: var(--border-strong); }
.badge--pill     { border-radius: var(--radius-pill); padding-inline: var(--sp-1); }


/* ============================================================
   6. TABS
   Course page: Syllabus / Instructor / Reviews / FAQ.
   Needs ui.js for keyboard arrow navigation and panel switching.

     <div class="tabs">
       <div class="tabs__list" role="tablist">
         <button class="tabs__tab" role="tab" aria-selected="true"
                 aria-controls="p1" id="t1">Syllabus</button>
       </div>
       <div class="tabs__panel" role="tabpanel" id="p1" aria-labelledby="t1">…</div>
     </div>
   ============================================================ */

.tabs__list {
  display: flex;
  gap: var(--sp-3);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tabs__list::-webkit-scrollbar { display: none; }

.tabs__tab {
  flex: none;
  min-height: var(--control-h);
  padding: 0 0 var(--sp-1);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;

  font-size: var(--fs-1);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.tabs__tab:hover { color: var(--text); }
.tabs__tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); }
.tabs__tab:focus-visible { box-shadow: var(--ring); border-radius: var(--radius-sm); outline: none; }

.tabs__panel { padding-top: var(--sp-3); }
.tabs__panel[hidden] { display: none; }


/* ============================================================
   7. MODAL
   Uses the native <dialog> element: focus trapping, Escape,
   inertness of the page behind it and the top layer are all free
   and already correct in every browser we target.

   Never use this for marketing. No exit-intent, no newsletter
   popup, no "wait! 20% off". Modals are for confirming an action
   the student initiated.
   ============================================================ */

.modal {
  width: min(32rem, calc(100vw - var(--sp-4)));
  max-height: min(42rem, calc(100dvh - var(--sp-4)));
  padding: 0;
  border: 0;
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  color: var(--text);
  box-shadow: 0 16px 48px rgba(32, 39, 37, 0.18);
}
.modal::backdrop { background: rgba(32, 39, 37, 0.55); }

.modal__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.modal__title { font-size: var(--fs-2); font-weight: var(--fw-semibold); line-height: var(--lh-tight); margin: 0; }
.modal__body  { padding: var(--sp-3); overflow-y: auto; }
.modal__foot  {
  display: flex; gap: var(--sp-1); justify-content: flex-end;
  padding: var(--sp-3);
  border-top: 1px solid var(--border);
}
.modal__close {
  flex: none;
  width: var(--control-h); height: var(--control-h);
  margin: calc(var(--sp-1) * -1) calc(var(--sp-1) * -1) 0 0;
  display: grid; place-items: center;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--text-muted); cursor: pointer; font-size: 1.25rem; line-height: 1;
}
.modal__close:hover { background: var(--bg-sunken); color: var(--text); }

/* Full-width stacked buttons on small screens — a 320px-wide
   phone cannot fit two side-by-side buttons at 44px tall. */
@media (max-width: 30rem) {
  .modal__foot { flex-direction: column-reverse; }
  .modal__foot .btn { width: 100%; }
}


/* ============================================================
   8. TOAST
   Confirmation after an action: "Demo class booked", "Payment
   submitted for review". Announced to screen readers via the
   live region in ui.js.

   .toast--inline is the same component pinned into the page —
   used for form-level success and failure messages at the top of
   login, signup and checkout.
   ============================================================ */

.toast-region {
  position: fixed;
  left: 50%;
  bottom: var(--sp-3);
  transform: translateX(-50%);
  z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--sp-1);
  width: min(28rem, calc(100vw - var(--sp-4)));
  pointer-events: none;
}

.toast {
  display: flex; align-items: flex-start; gap: var(--sp-1);
  padding: var(--sp-2);
  background: var(--ink);
  color: var(--text-inverse);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: var(--fs-0);
  line-height: 1.5;
  pointer-events: auto;
  animation: jf-toast-in var(--dur) var(--ease);
}
@keyframes jf-toast-in { from { opacity: 0; transform: translateY(var(--sp-1)); } }

.toast--inline {
  position: static; transform: none; width: 100%;
  margin-bottom: var(--sp-3);
  font-size: var(--fs-1);
  animation: none;
  border: 1px solid transparent;
}
.toast--inline.toast--success { background: var(--success-50); color: var(--success-700); border-color: currentColor; }
.toast--inline.toast--error   { background: var(--danger-50);  color: var(--danger-700);  border-color: currentColor; }
.toast--inline.toast--info    { background: var(--accent-subtle); color: var(--gold-800); border-color: var(--accent-border); }


/* ============================================================
   9. EMPTY STATE
   "No batches open for this course yet." Every list on the site
   has one. An empty list with no explanation reads as a broken
   page, and a broken page loses the sale.

   Always give it an action. An empty state with no next step is
   a dead end.
   ============================================================ */

.empty {
  text-align: center;
  padding: var(--sp-6) var(--sp-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-subtle);
}
.empty__title { font-size: var(--fs-2); font-weight: var(--fw-semibold); margin: 0 0 var(--sp-1); }
.empty__text  { color: var(--text-muted); margin: 0 auto var(--sp-3); max-width: 40ch; }


/* ============================================================
   10. SKELETON
   Shown while a list loads. Sized to the content it replaces, so
   nothing shifts when the real thing arrives — layout shift is
   both a Core Web Vitals penalty and the cheapest way to make a
   fast site feel slow.
   ============================================================ */

.skeleton {
  display: block;
  background: linear-gradient(90deg, var(--grey-100) 25%, var(--grey-200) 37%, var(--grey-100) 63%);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: jf-shimmer 1.4s ease infinite;
}
@keyframes jf-shimmer { from { background-position: 100% 50%; } to { background-position: 0 50%; } }

.skeleton--text  { height: 1rem; margin-bottom: var(--sp-1); }
.skeleton--title { height: 1.5rem; width: 60%; margin-bottom: var(--sp-2); }
.skeleton--media { aspect-ratio: 16 / 9; width: 100%; border-radius: var(--radius-lg); }
.skeleton--btn   { height: var(--control-h); width: 8rem; border-radius: var(--radius); }

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: var(--grey-100); }
}


/* ============================================================
   GRID — not a component, but every listing page needs it.
   auto-fit means the same markup gives 1 column at 360px and 3 at
   1120px with no breakpoints to maintain.
   ============================================================ */

.grid { display: grid; gap: var(--sp-3); }
.grid--cards { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17.5rem), 1fr)); }
.grid--2     { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }


/* ============================================================
   SITE CHROME — header and footer.

   Not one of the ten components, but every page has both, and
   they must live in a file that head.php already loads. Two
   stylesheets, uploaded one at a time, is the whole budget.
   ============================================================ */

/* ---- Header ---- */

.nav {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.nav__in { display: flex; align-items: center; gap: var(--sp-2); min-height: 4.5rem; }

.nav__brand {
  display: flex; align-items: baseline; gap: 1px;
  margin-right: var(--sp-3);
  font-size: var(--fs-2); font-weight: var(--fw-semibold);
  letter-spacing: -0.02em; line-height: 1;
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
.nav__brand span { color: var(--accent); }
.nav__brand:hover { text-decoration: none; }

/* The logo image. Height is fixed and width follows, so swapping
   the artwork later cannot change the header height.
   34px keeps the monogram legible without pushing the 64px header
   taller; on a narrow phone it drops to 28 so the nav row still
   fits beside the menu button. */
.nav__logo {
  display: block;
  height: 36px;
  width: auto;
  max-width: 62vw;
}
@media (max-width: 26rem) {
  .nav__logo { height: 28px; }
}

/* The footer lockup, on forest. Slightly larger because it is the
   sign-off rather than a control. */
.foot__logo {
  display: block;
  height: 42px;
  width: auto;
  max-width: 70vw;
}


.nav__links { display: flex; align-items: center; gap: var(--sp-3); list-style: none; margin: 0; padding: 0; }

.nav__link {
  display: inline-flex; align-items: center;
  min-height: var(--control-h);
  font-size: var(--fs-1); color: var(--grey-600);
  text-decoration: none; white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease);
}
.nav__link:hover { color: var(--ink); text-decoration: none; }
.nav__link[aria-current="page"] { color: var(--ink); font-weight: var(--fw-semibold);
             border-bottom-color: var(--accent-solid); border-bottom-width: 3px; }
.nav__link:focus-visible { box-shadow: var(--ring); border-radius: var(--radius-sm); outline: none; }

/* Supply side. Same row, quieter — a student's eye skips it. */
.nav__teach { margin-left: auto; }
.nav__teach .nav__link { color: var(--text-muted); }
.nav__teach .nav__link:hover { color: var(--accent-hover); }

.nav__auth {
  display: flex; align-items: center; gap: var(--sp-1);
  margin-left: var(--sp-1); padding-left: var(--sp-2);
  border-left: 1px solid var(--border);
}

.nav__burger { display: none; }

.nav__drawer { border-top: 1px solid var(--border); background: var(--bg-card); padding-block: var(--sp-1); }
.nav__drawer[hidden] { display: none; }
.nav__dlink {
  display: flex; align-items: center;
  min-height: var(--control-h);      /* 44px — every drawer row is a real tap target */
  font-size: var(--fs-1); color: var(--text); text-decoration: none;
  border-bottom: 1px solid var(--border);
}
.nav__dlink:last-child { border-bottom: 0; }
.nav__dlink:hover { color: var(--accent-hover); text-decoration: none; }

/* Collapse at 1024px, not 768px: "Learn in Small Groups" plus
   "Teach with IPTA" plus two buttons stops fitting well before
   tablet width. Measured, not guessed. */
@media (max-width: 64rem) {
  .nav__links, .nav__teach, .nav__login { display: none; }
  .nav__auth { margin-left: auto; padding-left: 0; border-left: 0; }
  .nav__burger {
    display: grid; place-items: center;
    width: var(--control-h); height: var(--control-h);
    background: none; color: var(--text);
    border: 1px solid var(--border-strong); border-radius: var(--radius);
    font-size: 1.25rem; line-height: 1; cursor: pointer;
  }
}
@media (min-width: 64.0625rem) {
  .nav__drawer { display: none; }
}

/* ---- Footer ---- */

.foot {
  margin-top: var(--sp-10);
  background: var(--forest);
  color: var(--text-inverse);
  padding-block: var(--sp-6) var(--sp-4);
}
.foot a { color: var(--on-forest); text-decoration: none; }
.foot a:hover { color: var(--white); text-decoration: underline; text-underline-offset: 2px; }
.foot a:focus-visible { box-shadow: var(--ring-inverse); border-radius: var(--radius-sm); outline: none; }

.foot__top { display: grid; gap: var(--sp-5); }
@media (min-width: 60rem) { .foot__top { grid-template-columns: 20rem 1fr; gap: var(--sp-8); } }

.foot__mark { font-size: var(--fs-2); font-weight: var(--fw-semibold); letter-spacing: -0.02em; margin: 0; }
.foot__mark span { color: var(--accent-decor); }
.foot__tag { font-size: var(--fs-0); color: var(--on-forest-muted); margin: var(--sp-1) 0 0; max-width: 34ch; line-height: 1.5; }

.foot__cols { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); }
.foot__col { display: flex; flex-direction: column; }
.foot__col a { min-height: 2.25rem; display: flex; align-items: center; font-size: var(--fs-1); }
.foot__h {
  font-size: var(--fs-0); font-weight: var(--fw-semibold); color: var(--white);
  margin: 0 0 var(--sp-1); text-transform: uppercase; letter-spacing: .06em;
}

.foot__bar {
  display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3);
  justify-content: space-between;
  margin-top: var(--sp-5); padding-top: var(--sp-3);
  border-top: 1px solid var(--forest-rule);
}
.foot__bar p { font-size: var(--fs-0); color: var(--on-forest-muted); margin: 0; }
.foot__bar strong { color: var(--white); font-weight: var(--fw-semibold); }

/* Wordmark. "GLOBAL" is set at the smallest step, letter-spaced and
   muted, so the lockup reads as one word at a glance and still
   carries the registered name. It is never a second line. */
.nav__brand-g, .foot__mark-g {
  margin-left: 0.4em;
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.nav__brand-g  { color: var(--accent); }
.foot__mark-g  { color: var(--accent-decor); }   /* 4.50 on forest — wordmark only */

/* Auth pages — login, signup, password reset. A narrow single
   column, centred, with nothing else on screen. One decision per
   page is the whole design. */
.auth { max-width: 26rem; margin-inline: auto; }
.auth .card { padding: var(--sp-4); }
