/* ---------------------------------------------------------------------------
   Ethel

   The visual world is a school exercise book: paper, a ruled margin, ink.
   That is not decoration — it is the object every one of these students
   already owns, and the thing Ethel is trying to be useful alongside.

   Three rules hold the whole design together:
     1. One content column, hung off a ruled margin. Each section gets a red
        mark on that rule, the way you would tick a margin in a book.
     2. Two pens, never more. Red is the teacher's: it marks sections, the
        brand, and the one primary action. Blue is the student's ballpoint:
        it carries information, data and status. Neither borrows the other's
        job, so a red thing always means "Ethel, act here" and a blue thing
        always means "here is what is true".
     3. No webfonts. Georgia and the system sans are already on the device.
        A site for people who pay per megabyte should not spend their money
        on typography, and the serif gives it a voice for free.

   Liquid Glass is on the sticky header and nowhere else. Content never sits
   on glass, so text contrast stays a fixed measured number instead of
   depending on what happens to scroll underneath.

   Colour is semantic and flips for dark mode. Contrast figures are measured,
   not guessed, and noted beside each value.
--------------------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  /* paper */
  --paper:       #fbf8f2;
  --paper-raise: #ffffff;
  --paper-sunk:  #f4f0e6;

  /* ink — ratios are against --paper */
  --ink:         #1c1b18;   /* 16.25:1 */
  --ink-2:       #56534b;   /*  7.24:1 */
  --ink-3:       #6e6a61;   /*  5.08:1 — floor for small text */

  /* the margin */
  --rule:        #e2ddd0;
  --rule-strong: #cfc8b7;

  /* One accent, one meaning: this is Ethel's mark, and the one place to
     act. It marks sections, the brand, and the primary button, and nothing
     else. Status does NOT use it — status is the green signal or plain ink,
     so that red never has to mean two things at once. */
  --red:         #a63229;   /*  6.37:1 on paper */
  --red-ink:     #ffffff;   /*  6.75:1 on red   */
  --red-wash:    #f7ece9;

  /* The student's ballpoint. An exercise book is written in blue and
     marked by the teacher in red, so blue carries everything the learner
     puts down — information, data, status — and never competes with the
     red pen for "act here". Four shades, all measured against paper. */
  --blue:        #1d4e89;   /*  7.91:1 on paper  */
  --blue-2:      #3a6ea8;   /*  4.98:1 on paper  */
  --blue-wash:   #eef3f9;
  --blue-line:   #c9d8ea;

  /* one signal colour, used only for status */
  --ok:          #2f6b46;

  --measure:     34rem;     /* ~66ch of body text */
  --col:         46rem;
  --gutter:      clamp(18px, 5vw, 40px);

  /* One curve for everything that arrives: fast out of the gate, long soft
     landing. Front-loading the movement is what makes a reveal feel quick
     even when it runs for half a second. */
  --ease-out:    cubic-bezier(.23, 1, .32, 1);

  --serif: Georgia, "Noto Serif", "Liberation Serif", serif;
  --sans:  ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
           "Helvetica Neue", Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:       #16150f;
    --paper-raise: #1f1e19;
    --paper-sunk:  #100f0b;

    --ink:         #efebe1;   /* 15.36:1 */
    --ink-2:       #aba69a;   /*  7.54:1 */
    --ink-3:       #948f83;   /*  5.67:1 on paper, 5.13:1 on the frosted card */

    --rule:        #2e2c25;
    --rule-strong: #443f35;

    --red:         #e8806d;   /*  6.74:1 on dark paper */
    --red-ink:     #1c1b18;   /*  6.35:1 on that red   */
    --red-wash:    #2a1d19;

    --blue:        #8ab4e8;   /*  8.51:1 on dark paper */
    --blue-2:      #6f9ad0;   /*  6.28:1 on dark paper */
    --blue-wash:   #18202b;
    --blue-line:   #2c3f57;

    --ok:          #6fbe8d;
  }
}

* { box-sizing: border-box; }

/* The hidden attribute loses to any author rule that sets display - .tag, for
   one, is inline-block - so it has to be made to win. Things waiting on
   releases.js are hidden until script fills them, and must actually be. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;          /* 17px, the platform reading default */
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

/* Long unbreakable tokens (an email address, a filename) must not push the
   layout sideways when someone scales text up to 200%. */
a, .mono, .dl-file, .pay .num, .pay .todo { overflow-wrap: anywhere; }

/* Grid and flex children default to min-content width, which lets a long
   token widen the whole track. Never let them. */
.donate-grid > *, .dl-grid > *, .duo > *, .shelf > *, .foot-in > * { min-width: 0; }

/* --- the column and its margin ----------------------------------------- */

.wrap {
  width: 100%;
  max-width: calc(var(--col) + var(--gutter) + 20px);
  margin: 0 auto;
  padding: 0 20px;
}

/* Two widths, and only two:
     - boxed card grids (.dl-grid, .donate-grid) and the two-column split
       (.duo) take the full column, because they are scanned, not read
     - everything else — prose, hairline lists, notices, steps — stays at
       --measure, because long lines hurt reading
   A hairline list at one width and a hairline list at another reads as a
   mistake, so .points and .shelf deliberately match. */

/* Content hangs off a ruled margin, like schoolwork. */
.col {
  border-left: 1px solid var(--rule);
  padding-left: var(--gutter);
  max-width: var(--col);
}

/* Each section is marked on the rule. This is the signature: it says
   "new section" the way a tick in a margin does, and nothing else in the
   design is allowed to be this loud. */
.col > h2,
.col > h1 {
  position: relative;
}
.col > h2::before,
.col > h1::before {
  content: "";
  position: absolute;
  left: calc(-1px - var(--gutter));
  top: 0.34em;
  width: 3px;
  height: 1.15em;
  background: var(--red);
}

/* --- type --------------------------------------------------------------- */

h1, h2, h3 { margin: 0; font-weight: 400; }

h1 {
  font-family: var(--serif);
  font-size: clamp(2.05rem, 6.2vw, 3.15rem);
  line-height: 1.12;
  letter-spacing: -0.014em;
  max-width: 17ch;
  text-wrap: balance;
}

h2 {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 3.6vw, 2.05rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  max-width: 24ch;
  text-wrap: balance;
}

h3 {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.005em;
}

p { margin: 0 0 1.05em; max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }

/* Buttons and links draw their own pressed state, so Android's grey tap
   flash would be a second, cruder copy of it. */
a, button, .btn { -webkit-tap-highlight-color: transparent; }

.lede {
  font-size: 1.15rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: var(--measure);
}

.dim   { color: var(--ink-3); }
.muted { color: var(--ink-2); }
.small { font-size: 0.9375rem; }   /* 15px — never below this for prose */
.mono  { font-family: var(--mono); font-size: 0.88em; }

section { padding: clamp(48px, 8vw, 84px) 0; }

/* --- header ------------------------------------------------------------- */

/* Liquid Glass lives on the floating functional layer and nowhere else.
   Content never sits on glass: cards, notices and the page body stay on
   opaque surfaces, so text contrast is a fixed number rather than whatever
   happens to scroll underneath. */
.site-head {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 70%, transparent);
  backdrop-filter: saturate(185%) blur(20px);
  -webkit-backdrop-filter: saturate(185%) blur(20px);
  border-bottom: 1px solid transparent;
  transition: background .25s ease, border-color .25s ease;
}

/* The specular edge: what separates glass from a blurred rectangle. It only
   appears once there is content underneath to catch. */
.site-head::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--blue-2) 55%, transparent) 30%,
    color-mix(in srgb, var(--blue-2) 55%, transparent) 70%,
    transparent);
  opacity: 0; transition: opacity .25s ease; pointer-events: none;
}
.site-head.is-stuck {
  background: color-mix(in srgb, var(--paper) 84%, transparent);
  border-bottom-color: var(--rule);
}
.site-head.is-stuck::after { opacity: 1; }

/* No backdrop-filter support, or the person asked for less transparency:
   fall back to an honest opaque bar. */
@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .site-head { background: var(--paper); border-bottom-color: var(--rule); }
}
@media (prefers-reduced-transparency: reduce) {
  .site-head {
    background: var(--paper); border-bottom-color: var(--rule);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .site-head::after { display: none; }
}

.head-in {
  display: flex; align-items: center; gap: 16px;
  min-height: 56px;
  max-width: calc(var(--col) + var(--gutter) + 20px);
  margin: 0 auto; padding: 0 20px;
}

.brand {
  display: flex; align-items: center; gap: 9px;
  color: var(--ink); text-decoration: none;
  font-family: var(--serif); font-size: 1.22rem; letter-spacing: -0.01em;
  min-height: 44px;                        /* 44pt touch target */
  padding-right: 8px;
}
/* The app's own icon, so the header, the browser tab and the phone's home
   screen all carry the same mark. It replaced a plain red rule here. */
.brand-mark { width: 28px; height: 28px; flex: none; display: block; }
.brand b { font-weight: 400; }

.head-nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.head-nav a {
  color: var(--ink-2); text-decoration: none;
  font-size: 0.9375rem;
  padding: 10px 11px;           /* 44px tall target */
  border-radius: 6px;
  transition: color .15s ease, background .15s ease;
}
@media (max-width: 640px) { .head-nav .hide-sm { display: none; } }

/* --- beta line ---------------------------------------------------------- */

.beta-strip {
  background: var(--paper-sunk);
  border-bottom: 1px solid var(--rule);
  font-size: 0.9375rem;
  color: var(--ink-2);
}
.beta-strip .wrap {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px;
  padding-top: 10px; padding-bottom: 10px;
}
.beta-strip b { color: var(--ink); font-weight: 600; }

/* --- hero --------------------------------------------------------------- */

.hero { padding: clamp(44px, 9vw, 92px) 0 clamp(36px, 6vw, 60px); }
.hero h1 { margin-bottom: 22px; }
.hero .lede { margin-bottom: 28px; }

/* Breadcrumbs. Quiet on purpose: they are for finding your way back, and
   for search engines, not for reading. */
.crumbs { margin: 0 0 18px; font-size: 0.875rem; color: var(--ink-3); }
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; }
.crumbs li + li::before { content: "\203A"; margin: 0 8px; color: var(--rule-strong); }
.crumbs a { color: var(--ink-2); }
.crumbs [aria-current] { color: var(--ink-3); }

/* The not-found page: one column, the way back, and nothing else. */
.lost-links { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 10px; }
.lost-links a { font-size: 1.0625rem; }

/* A plain, factual line instead of a grid of big numbers. */
.facts {
  font-size: 0.9375rem; color: var(--ink-3);
  border-top: 1px solid var(--rule);
  padding-top: 14px; margin-top: 32px;
  max-width: var(--measure);
}
.facts b { color: var(--blue); font-weight: 600; font-variant-numeric: tabular-nums; }

/* --- buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px; padding: 11px 20px;
  border-radius: 7px; border: 1px solid transparent;
  font-family: inherit; font-size: 1rem; font-weight: 600;
  text-decoration: none !important; cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform 140ms var(--ease-out);
}
.btn-primary { background: var(--red); color: var(--red-ink); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--rule-strong); }
.btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
/* Pressed. A download starts in the background with nothing on the page to
   show for it, so the button itself has to say the tap landed - or people
   tap again and get two copies of a 30 MB file on a metered bundle. */
.btn:active { transform: scale(.97); }

.btn-row { display: flex; flex-wrap: wrap; gap: 10px; }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --- plain list of points (replaces the card grid) ---------------------- */

.points { margin: 30px 0 0; padding: 0; list-style: none; max-width: var(--measure); }
.points li { border-top: 1px solid var(--rule); padding: 18px 0; }
.points li:last-child { border-bottom: 1px solid var(--rule); }
.points h3 { margin-bottom: 3px; }
.points p { color: var(--ink-2); font-size: 0.9375rem; margin: 0; }

/* --- the shelf ---------------------------------------------------------- */

.shelf { display: grid; gap: 0; margin-top: 30px; max-width: var(--measure); }

.card {
  display: block; text-decoration: none; color: inherit;
  border-top: 1px solid var(--rule);
  padding: 22px 0;
}
.shelf .card:last-child { border-bottom: 1px solid var(--rule); }
a.card h3 { transition: color .15s ease; }
a.card:hover { text-decoration: none; }

.card-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.card h3 { font-size: 1.15rem; font-family: var(--serif); font-weight: 400; }
.card p { color: var(--ink-2); font-size: 0.9375rem; margin: 6px 0 0; }
.card.is-soon h3 { color: var(--ink-3); }

/* --- status tags -------------------------------------------------------- */

.tag {
  display: inline-block;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.02em;
  padding: 2px 8px; border-radius: 4px;
  border: 1px solid var(--rule-strong); color: var(--ink-3);
  white-space: nowrap;
}
.tag-beta { color: var(--blue); border-color: var(--blue-line); background: var(--blue-wash); }
.tag-live { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 50%, transparent); }
.tag-ver  { font-family: var(--mono); font-weight: 500; color: var(--blue); border-color: var(--blue-line); }

/* --- downloads ----------------------------------------------------------
   The download cards are frosted, so they need something behind them worth
   blurring — over a flat background backdrop-filter resolves to that same
   flat colour and the frost is invisible. This wash is that something: two
   soft pools in the two pens' colours, kept faint enough that the worst
   point under a card still leaves every text style above 4.5:1.
-------------------------------------------------------------------------- */

.frost-bed { position: relative; isolation: isolate; }
.frost-bed::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(52% 48% at 18% 72%,
      color-mix(in srgb, var(--blue-line) 62%, transparent), transparent 72%),
    radial-gradient(44% 42% at 84% 88%,
      color-mix(in srgb, var(--red-wash) 78%, transparent), transparent 72%);
}

.dl-grid { display: grid; gap: 14px; margin-top: 8px; }
@media (min-width: 720px) { .dl-grid { grid-template-columns: 1fr 1fr; } }

.dl {
  /* Pinned at 82%: opaque enough that the text contrast is a fixed number
     however the wash falls behind it, sheer enough that the blur reads. */
  background: color-mix(in srgb, var(--paper-raise) 82%, transparent);
  backdrop-filter: saturate(170%) blur(16px);
  -webkit-backdrop-filter: saturate(170%) blur(16px);
  border: 1px solid color-mix(in srgb, var(--paper-raise) 55%, var(--rule));
  border-radius: 10px;
  padding: 22px;
  display: flex; flex-direction: column;
  position: relative;
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px -12px rgba(0,0,0,.10);
}

/* The lit top edge. Without it a frosted panel reads as a grey box. */
.dl::before {
  content: ""; position: absolute; left: 12px; right: 12px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, #fff 70%, transparent), transparent);
  pointer-events: none;
}
@media (prefers-color-scheme: dark) {
  .dl::before {
    background: linear-gradient(90deg, transparent,
      color-mix(in srgb, #fff 22%, transparent), transparent);
  }
}

/* Where glass is unavailable or unwanted, the card goes fully opaque and the
   wash behind it is removed, so nothing depends on translucency. */
@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .dl { background: var(--paper-raise); border-color: var(--rule); }
  .frost-bed::before { display: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .dl {
    background: var(--paper-raise); border-color: var(--rule);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .dl::before { display: none; }
  .frost-bed::before { display: none; }
}
.dl-plat { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; margin-bottom: 14px; }
.dl-plat h3 { font-size: 1.08rem; }

.dl-meta { margin: 0 0 20px; padding: 0; list-style: none; font-size: 0.9375rem; color: var(--ink-3); }
.dl-meta li { padding: 2px 0; }
.dl .btn { width: 100%; margin-top: auto; }
.dl-file { font-family: var(--mono); font-size: 0.875rem; color: var(--blue-2); margin-top: 10px; text-align: center; }

/* --- the story ---------------------------------------------------------- */

.story { max-width: var(--measure); }
.story p {
  font-family: var(--serif);
  font-size: 1.16rem;
  line-height: 1.62;
  color: var(--ink);
}
.story p + p { margin-top: 1.1em; }

.pull {
  font-family: var(--serif);
  font-size: 1.32rem;
  line-height: 1.4;
  color: var(--ink);
  margin: 34px 0;
  padding-left: 20px;
  border-left: 3px solid var(--red);
  max-width: 30rem;
}

/* --- steps (numbered because installing IS a sequence) ------------------ */

.steps { counter-reset: s; margin: 0; padding: 0; list-style: none; max-width: var(--measure); }
.steps li {
  counter-increment: s;
  position: relative;
  padding: 14px 0 14px 34px;
  border-top: 1px solid var(--rule);
  color: var(--ink-2);
  font-size: 0.9375rem;
}
.steps li:last-child { border-bottom: 1px solid var(--rule); }
.steps li::before {
  content: counter(s) ".";
  position: absolute; left: 0; top: 14px;
  font-family: var(--mono); font-size: 0.875rem;
  color: var(--blue);          /* the learner's own numbering, not a mark */
}
.steps b { color: var(--ink); font-weight: 600; }

/* --- notices ------------------------------------------------------------ */

.notice {
  border: 1px solid var(--blue-line);
  border-radius: 10px;
  background: var(--blue-wash);
  padding: 20px 22px;
  font-size: 0.9375rem;
  color: var(--ink-2);
  max-width: var(--measure);
}
.notice h3 { color: var(--ink); margin-bottom: 7px; }
.notice.is-open { border-left: 3px solid var(--ok); }
.notice.is-limited { border-left: 3px solid var(--rule-strong); }
.notice ul { margin: 10px 0 0; padding-left: 17px; }
.notice li { margin-bottom: 6px; }
.notice li:last-child { margin-bottom: 0; }
.notice p { max-width: none; }

.stack { display: grid; gap: 14px; }

/* --- donate ------------------------------------------------------------- */

.donate-grid { display: grid; gap: 14px; margin-top: 28px; }   /* structure: full column */
@media (min-width: 640px) { .donate-grid { grid-template-columns: 1fr 1fr; } }

.pay {
  border: 1px solid var(--rule);
  border-radius: 10px;
  background: var(--paper-raise);
  padding: 20px;
}
.pay h3 { margin-bottom: 6px; }
.pay .num {
  display: inline-block;
  font-family: var(--mono); font-size: 1.05rem;
  color: var(--ink); margin: 4px 0;
  /* One tap selects the whole number, ready to paste into the mobile
     money menu. */
  -webkit-user-select: all; user-select: all;
}
.pay a.num { color: var(--red); }
.pay .todo {
  font-family: var(--mono); font-size: 0.8125rem;
  color: var(--red);
  border: 1px dashed var(--red);
  background: var(--red-wash);
  border-radius: 6px; padding: 8px 10px; margin-top: 10px;
}

/* --- versions ----------------------------------------------------------- */

.ver { border-top: 1px solid var(--rule); padding: 20px 0; max-width: var(--measure); }
.ver:last-child { border-bottom: 1px solid var(--rule); }
.ver-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; }
.ver-num { font-family: var(--mono); font-size: 1rem; font-weight: 600; color: var(--blue); }
.ver ul { margin: 12px 0 0; padding-left: 17px; color: var(--ink-2); font-size: 0.9375rem; }
.ver li { margin-bottom: 5px; }

/* --- two-column prose at wide widths ------------------------------------ */

.duo { display: grid; gap: 40px; }
@media (min-width: 760px) { .duo { grid-template-columns: 1fr 1fr; gap: 44px; } }
.duo > div { min-width: 0; }
.duo h3 { margin-bottom: 14px; }

/* --- ads ---------------------------------------------------------------- */

.ad-slot { max-width: calc(var(--col) + var(--gutter) + 20px); margin: 0 auto; padding: 0 20px; }
.ad-slot:empty { display: none; }

/* --- footer ------------------------------------------------------------- */

.site-foot {
  border-top: 1px solid var(--rule);
  background: var(--paper-sunk);
  padding: 40px 0 52px;
  font-size: 0.9375rem;
  color: var(--ink-3);
}
.foot-in { display: grid; gap: 26px; }
@media (min-width: 680px) { .foot-in { grid-template-columns: 2fr 1fr 1fr; gap: 32px; } }
.site-foot strong { display: block; color: var(--ink-2); font-weight: 600; margin-bottom: 8px; }
.site-foot a {
  display: flex; align-items: center; min-height: 44px;   /* 44pt touch target */
  color: var(--ink-2); text-decoration: none;
}
.site-foot p { max-width: 30rem; }

/* --- motion --------------------------------------------------------------
   Progressive enhancement: .js-motion is set by script, so with JS off or
   broken every element is simply visible. Only opacity and transform are
   animated — both are compositor-only, which matters on the cheap Android
   phones this site is actually read on.
-------------------------------------------------------------------------- */

/* Opacity and movement share one curve. They used to run on two - plain
   `ease` for the fade, a custom curve for the rise - so each element was
   still visibly fading in after it had stopped moving, and the arrival
   read as two events instead of one. */
.js-motion .reveal { opacity: 0; transform: translateY(10px); }
.js-motion .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
}

/* The section mark is drawn rather than switched on — a pen stroke down the
   margin. It is the one orchestrated moment in the design. */
.js-motion .col > h1::before,
.js-motion .col > h2::before { transform: scaleY(0); transform-origin: top; }
.js-motion .col > h1.is-in::before,
.js-motion .col > h2.is-in::before {
  transform: scaleY(1);
  transition: transform .5s var(--ease-out) .06s;
}

/* --- hover ---------------------------------------------------------------
   Behind a query for a real pointer. Most people reading this are on a
   phone, which has no hover but fakes one on tap and leaves it stuck: the
   footer link stayed underlined and the nav item stayed shaded after the
   page had already scrolled to where it pointed.
-------------------------------------------------------------------------- */

@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration-thickness: 2px; }
  .head-nav a:hover { color: var(--ink); background: var(--paper-sunk); }
  .btn-primary:hover { background: color-mix(in srgb, var(--red) 88%, var(--ink)); }
  .btn-ghost:hover { background: var(--paper-sunk); }
  a.card:hover h3 { color: var(--red); }
  .site-foot a:hover { color: var(--ink); text-decoration: underline; }
}

/* --- the lesson figure (home page) -----------------------------------------
   A real check question from the Principles of Accounts course, shown the way
   Ethel handles a wrong answer. Static on purpose: it is a picture of the
   product, not a copy of it, so nothing on it is clickable.
-------------------------------------------------------------------------- */

.lesson-fig {
  margin: 36px 0 0;
  background: var(--paper-raise);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 22px 22px 20px;
  max-width: 30rem;
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 10px 30px -18px rgba(0,0,0,.18);
}
.lesson-fig .lf-course {
  font-size: .8125rem; font-weight: 600; letter-spacing: .02em;
  color: var(--blue); margin: 0 0 10px;
}
.lesson-fig .lf-q { font-weight: 600; margin: 0 0 14px; line-height: 1.45; }
.lesson-fig ol { list-style: none; margin: 0 0 16px; padding: 0; display: grid; gap: 8px; }
.lesson-fig li {
  display: flex; gap: 10px; align-items: baseline;
  border: 1px solid var(--rule); border-radius: 8px;
  padding: 9px 12px; font-size: .9375rem; color: var(--ink-2);
}
.lesson-fig li .lf-key { font-family: var(--mono); font-size: .8125rem; color: var(--ink-3); }
.lesson-fig li.lf-chosen { border-color: var(--red); color: var(--ink); }
/* The mark is the teacher's pen, so it is red - and it is a word, not only a
   colour, so it reads without colour too. */
.lesson-fig li .lf-mark {
  margin-left: auto; font-size: .8125rem; font-weight: 600; color: var(--red);
  white-space: nowrap;
}
.lesson-fig .lf-explain {
  border-left: 3px solid var(--red);
  padding: 2px 0 2px 14px; margin: 0 0 12px;
  font-family: var(--serif); font-size: 1.02rem; line-height: 1.5; color: var(--ink);
}
.lesson-fig .lf-next { font-size: .9375rem; color: var(--ink-2); margin: 0; }
.lesson-fig figcaption {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule);
  font-size: .875rem; color: var(--ink-3);
}

/* --- wide screens: the open exercise book -----------------------------------
   On a laptop the single column left 60 percent of the screen empty and read
   as a phone page. Wide, the margin becomes a real column: section headings
   sit in it and stay put while their section scrolls past, the ruled line
   runs between margin and page, and the content takes the rest. Prose keeps a
   reading measure; card grids use the full width. Phones are untouched.
-------------------------------------------------------------------------- */

@media (min-width: 1000px) {
  :root {
    --col: 70rem;
    --margin-col: 16.5rem;
    --margin-gap: 3.5rem;
    --measure: 38rem;
  }

  .col {
    display: grid;
    grid-template-columns: var(--margin-col) minmax(0, 1fr);
    column-gap: var(--margin-gap);
    border-left: 0;
    padding-left: 0;
    position: relative;
  }
  /* the ruled line, now between the margin and the page */
  .col::before {
    content: ""; position: absolute; top: 0; bottom: 0;
    left: calc(var(--margin-col) + var(--margin-gap) / 2);
    width: 1px; background: var(--rule);
  }
  .col > * { grid-column: 2; }
  .col > h1,
  .col > h2 {
    grid-column: 1;
    grid-row: 1 / span 40;
    align-self: start;
    position: sticky;
    top: 5.5rem;
    max-width: none;
    font-size: clamp(1.55rem, 1.9vw, 1.9rem);
  }
  .col > h1 { font-size: clamp(2.1rem, 2.8vw, 2.6rem); }
  /* the section mark sits on the ruled line, beside its heading */
  .col > h1::before,
  .col > h2::before {
    left: calc(100% + var(--margin-gap) / 2 - 1px);
  }
  /* inline top margins written for the stacked layout would push content
     below its heading; in two columns they start level */
  .col > h2 + * { margin-top: 0 !important; }

  /* Home hero: headline and pitch on the left, the lesson on the right. */
  .col.hero-split {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    column-gap: 4.5rem;
    align-items: center;
    border-left: 1px solid var(--rule);
    padding-left: var(--gutter);
  }
  .col.hero-split::before { display: none; }
  .col.hero-split > * { grid-column: 1; }
  .col.hero-split > h1 {
    grid-row: auto; position: relative; top: auto;
    font-size: clamp(2.6rem, 4vw, 3.4rem);
  }
  .col.hero-split > h1::before { left: calc(-1px - var(--gutter)); }
  .col.hero-split > .lesson-fig {
    grid-column: 2; grid-row: 1 / span 4; align-self: center;
    margin: 0; justify-self: end; width: 100%;
  }

  /* lists of points read better two across once there is room */
  .points {
    display: grid; grid-template-columns: 1fr 1fr; column-gap: 2.5rem;
    max-width: none;
  }
  .points li:nth-last-child(2):nth-child(odd) { border-bottom: 1px solid var(--rule); }

  .shelf, .donate-grid { max-width: none; }
  .donate-grid { grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); }

  .foot-in { grid-template-columns: 2fr 1fr 1fr; }
}

/* --- preferences -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .js-motion .reveal,
  .js-motion .reveal.is-in { opacity: 1 !important; transform: none !important; }
  .js-motion .col > h1::before,
  .js-motion .col > h2::before { transform: none !important; }
}

/* Increased contrast has to be written per theme. A single hard-coded value
   here was darkening --ink-3 in BOTH appearances, which took dark mode from
   5.67:1 down to 1.97:1 — the exact opposite of what the setting asks for. */
@media (prefers-contrast: more) {
  :root {
    --ink-2: var(--ink);
    --ink-3: #4a473f;        /*  8.75:1 on paper */
    --rule: var(--rule-strong);
  }
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
  :root {
    --ink-2: var(--ink);
    --ink-3: #cfcabd;        /* 10.74:1 on dark paper */
    --rule: var(--rule-strong);
  }
}
