/* ILO FLOW — advertising and consent surfaces.
   ---------------------------------------------------------------------------
   Loaded on every page. It styles nothing that exists unless js/ads.js has
   decided to draw it, so the cost of shipping it with ads disabled is the
   ~2 KB of this file and nothing else.

   Two things here are doing real work rather than decoration:

     1. The slot RESERVES its height before the ad arrives. An ad that appears
        and shoves the page down is the largest CLS regression a display unit
        can cause, and Google's own Core Web Vitals report is what surfaces it.
        min-height is set from the same responsive breakpoints the unit itself
        uses, so the reserved box and the delivered ad are close to the same
        size in practice.

     2. The slot COLLAPSES to nothing when unfilled. AdSense leaves the <ins>
        empty when it has no inventory for a region, which is common in
        East Africa outside peak hours. A reserved 280px of blank space at the
        bottom of Home looks like a rendering fault, so an empty unit takes its
        label and its margin with it.  --------------------------------------- */

/* --- 1. THE SLOT ---------------------------------------------------------- */

.ad-slot {
  display: block;
  margin: var(--sp-7) auto 0;
  max-width: 728px;
  padding: 0;
  border-top: 1px solid var(--rule-soft);
  /* Reserved space. See note 1 above. */
  min-height: 140px;
  /* contain:layout stops a misbehaving unit from affecting the rest of the
     page's layout calculations; content-visibility keeps an off-screen slot out
     of the initial layout pass entirely. */
  contain: layout style;
}

.ad-slot-label {
  display: block;
  padding: var(--sp-2) 0 var(--sp-1);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  /* --parchment-dim on --ink measures ~7.4:1, comfortably past AA for small
     text. It must stay legible: an unlabelled ad that looks like a lesson card
     is an AdSense policy violation, not a style choice. */
  color: var(--parchment-dim);
}

.ad-slot-ins {
  display: block;
  width: 100%;
  min-height: 100px;
}

/* Unfilled, blocked, or failed to load. See note 2 above. */
.ad-slot.is-empty,
.ad-slot:has(> .adsbygoogle[data-ad-status="unfilled"]) {
  display: none;
}

/* :has() is unsupported on older Safari and Firefox ESR, where the rule above
   is dropped entirely. js/ads.js therefore also sets .is-empty from script, so
   collapse does not depend on a selector the browser may not understand. */

@media (min-width: 720px) {
  .ad-slot { min-height: 180px; }
}

/* Print: an advertisement has no business on a printed financial statement,
   and this product's statements are printed artefacts. */
@media print {
  .ad-slot, .consent-banner { display: none !important; }
}


/* --- 2. THE CONSENT BANNER ------------------------------------------------ */

.consent-banner {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 9000;
  background: var(--ledger-2);
  border-top: 1px solid var(--rule);
  box-shadow: 0 -12px 32px rgba(0, 0, 0, .34);
  /* Clears the iOS home indicator. The app already uses viewport-fit=cover,
     so without this the reject button sits under the system gesture bar and is
     close to untappable — which would make "Agree" the only reachable answer. */
  padding: var(--sp-4) var(--sp-4) calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
  animation: consentRise .32s var(--ease) both;
}

@keyframes consentRise {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

.consent-inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
  align-items: center;
  justify-content: space-between;
  max-width: 1100px;
  margin: 0 auto;
}

.consent-copy { flex: 1 1 420px; min-width: 0; }

.consent-copy h2 {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--parchment);
}

/* js/ads-consent.js moves focus to this heading when the banner opens, so a
   screen reader announces what has appeared rather than leaving it unmentioned
   at the bottom of the document. The heading carries tabindex="-1" to receive
   that focus.

   No focus ring is drawn. tabindex="-1" means the heading is NOT reachable by
   Tab, so it is not a user interface component in the sense of WCAG 2.4.7 and
   needs no visible indicator — whereas Chrome, which matches :focus-visible for
   a programmatic focus when there has been no pointer interaction yet, drew a
   full-width gold rectangle across the top of the banner on every page load.
   That rectangle reads as an error state on a prompt nobody navigated to.

   Every control inside the banner keeps its own focus ring; only this
   non-interactive announcement target loses one. */
.consent-copy h2:focus,
.consent-copy h2:focus-visible { outline: none; box-shadow: none; }

.consent-copy p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--parchment-dim);
}

.consent-links { margin-top: var(--sp-2) !important; }
.consent-links a { color: var(--entrust); text-decoration: underline; }
.consent-links span { margin: 0 var(--sp-2); color: var(--rule); }

.consent-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  flex: 0 1 auto;
}

/* Both answers get the same footprint. A reject button rendered smaller or
   greyer than accept is the classic consent dark pattern, and it is also the
   thing a regulator screenshots first. Equal size, equal contrast, equal
   reading order; only the fill differs, and that difference is the app's
   ordinary primary/ghost pairing used everywhere else. */
.consent-actions .btn { min-height: 44px; padding: 0 var(--sp-5); white-space: nowrap; }

@media (max-width: 640px) {
  .consent-inner { gap: var(--sp-4); }
  .consent-actions { width: 100%; }
  .consent-actions .btn { flex: 1 1 100%; }
}

/* The banner is fixed, so without this it covers the last few lines of every
   screen — including the ad slot immediately above it. */
body.has-consent-banner .app { padding-bottom: 220px; }
@media (min-width: 641px) {
  body.has-consent-banner .app { padding-bottom: 150px; }
}

/* --- 3. AD PREFERENCES CONTROL ------------------------------------------- */

.ad-prefs-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--entrust);
  text-decoration: underline;
  cursor: pointer;
}
.ad-prefs-link:focus-visible {
  outline: 2px solid var(--entrust);
  outline-offset: 3px;
  border-radius: 2px;
}


/* --- 4. ACCESSIBILITY PREFERENCES ---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .consent-banner { animation: none; }
}

@media (prefers-contrast: more) {
  .ad-slot-label { color: var(--parchment); }
  .consent-copy p { color: var(--parchment); }
  .consent-banner { border-top-width: 2px; }
}

/* forced-colors strips every custom colour. Keep the structural borders, which
   are what separate the banner and the ad label from real content once the
   palette is gone. */
@media (forced-colors: active) {
  .consent-banner { border-top: 2px solid CanvasText; background: Canvas; }
  .ad-slot { border-top: 1px solid CanvasText; }
  .ad-slot-label { color: CanvasText; }
}


/* --- 5. SITE FOOTER ------------------------------------------------------- */
/* Lives here rather than in base.css because the footer exists for the same
   reason the rest of this file does: the AdSense site review needs a crawlable
   path from the landing page to the privacy policy. It is styled to read as
   part of the product, not as a compliance bolt-on. */

.site-footer {
  margin-top: var(--sp-8);
  padding: var(--sp-6) var(--sp-4) calc(var(--sp-6) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--rule-soft);
  text-align: center;
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  align-items: center;
  justify-content: center;
  margin-bottom: var(--sp-4);
}

.site-footer-links a,
.site-footer-links .ad-prefs-link {
  font-size: 13px;
  color: var(--parchment-dim);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  /* 44px of tappable height on a touch screen. These sit at the very bottom of
     a long scroll, which is the worst place to put a 13px target. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.site-footer-links a:hover,
.site-footer-links a:focus-visible,
.site-footer-links .ad-prefs-link:hover,
.site-footer-links .ad-prefs-link:focus-visible {
  color: var(--entrust);
  border-bottom-color: var(--entrust);
}

.site-footer-links a:focus-visible,
.site-footer-links .ad-prefs-link:focus-visible {
  outline: 2px solid var(--entrust);
  outline-offset: 4px;
  border-radius: 2px;
}

.site-footer-credit {
  margin: 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--parchment-dim);
}

.site-footer-copy { display: block; opacity: .75; }

@media (forced-colors: active) {
  .site-footer { border-top: 1px solid CanvasText; }
  .site-footer-links a, .site-footer-credit { color: CanvasText; }
}
