/* ============================================================
   ExamCrack - white surface and drifting field for the demo page
   (Sep 15 2026)

   Loaded by demo.html only, AFTER the inline style block in its head, so these
   rules win on equal specificity.

   WHY THE SCOPE MATTERS: demo.html loads admin.css and exam-light.css, and
   exam-light.css is shared with exam.html, result.html, demo-result.html,
   exam-landing.html and card.html. Every rule here is therefore scoped to
   body.demo-page, which is a class only demo.html carries, so those five pages
   are untouched.

   The demo page was already light, so this is a visual pass rather than a
   conversion: the page goes white, the muted text ramp is corrected for AA
   contrast on white, and the surfaces, type, buttons and cards are brought onto
   the same language as the landing page. The flows, the form, the consent
   handling and the toast are deliberately not touched.

   Text colours measured on white before being written, ratios noted inline.
   Nothing below 4.5:1 ships.
   ============================================================ */

/* The drifting field's palette. These have to sit on :root, not on the body
   class, because js/welcome-next-bg.js reads them from the root element. That is
   safe here only because this file is loaded by one page. Three hues give the
   multi-colour drift; a page defining only --wn-net gets a single colour. */
:root {
  --wn-net:   #2f80ed;
  --wn-net-2: #6d5ef6;
  --wn-net-3: #06b6d4;
}

body.demo-page {
  /* surface */
  --bg: #ffffff;
  --panel: #ffffff;
  --surface: #f7f9fc;
  --surface-2: #f1f4f9;

  /* text. --text-4 was #9ca1a8, which measures 2.44:1 on white and fails AA;
     it is used for the footer and the optional field labels, so it matters. */
  --text-1: #0d1117;   /* 18.92:1 */
  --text-2: #334155;   /* 10.35:1 */
  --text-3: #55606e;   /*  6.39:1 */
  --text-4: #6b7280;   /*  4.83:1 */

  --border-subtle: rgba(13, 17, 23, 0.06);
  --border: rgba(13, 17, 23, 0.10);
  --accent: #4f46e5;        /* 6.29:1 on white */
  --accent-hover: #4338ca;  /* 7.90:1 */

  background-color: #ffffff;
}

body.demo-page .demo-wrap {
  position: relative;
  z-index: 1;
  max-width: 980px;
  padding: 34px 24px 76px;
}

/* The field sits behind everything, so where it runs under the header, the
   title and the steps it is masked back. Content is on top of this, and the
   canvas is below it, which is why the wrap is given its own stacking context.
   The grid of papers below is left unmasked, where the field has room. */
body.demo-page .demo-wrap::before {
  content: '';
  position: absolute;
  left: -40px; right: -40px; top: -34px;
  height: 620px;
  z-index: -1;
  pointer-events: none;
  background-image: linear-gradient(180deg,
    rgba(255, 255, 255, 0.965) 0%,
    rgba(255, 255, 255, 0.93) 52%,
    rgba(255, 255, 255, 0) 100%);
}

/* ---------- header row ---------- */

body.demo-page .demo-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-1);
}
body.demo-page .demo-brand::before {
  content: 'E';
  width: 26px; height: 26px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background-image: linear-gradient(135deg, #2f80ed 0%, #6d5ef6 100%);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}
body.demo-page .demo-brand span { color: var(--text-1); }

/* ---------- type ---------- */

body.demo-page .demo-title {
  font-size: clamp(30px, 4.6vw, 50px);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
  color: var(--text-1);
  max-width: 19ch;
  margin: 0 0 16px;
}
body.demo-page .demo-sub {
  font-size: 17px;
  line-height: 1.62;
  color: var(--text-2);
  max-width: 62ch;
}

body.demo-page .exam-section-title {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: 0 0 10px;
  border-bottom: 1px solid var(--border);
  margin: 0 0 16px;
}
body.demo-page .exam-section { margin: 0 0 38px; }

/* ---------- the step list ---------- */

body.demo-page .steps { gap: 13px; margin: 24px 0 0; }
body.demo-page .steps li {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--text-2);
  padding-left: 30px;
}
body.demo-page .steps li::before {
  content: '';
  left: 0; top: 6px;
  width: 16px; height: 16px;
  border-radius: 999px;
  background-color: #eef2ff;
  box-shadow: inset 0 0 0 1px rgba(79, 70, 229, 0.22);
}
body.demo-page .steps li::after {
  content: '';
  position: absolute;
  left: 5px; top: 10.5px;
  width: 6px; height: 3px;
  border-left: 1.6px solid var(--accent);
  border-bottom: 1.6px solid var(--accent);
  rotate: -45deg;
}
body.demo-page .steps li b { color: var(--text-1); font-weight: 600; }

/* ---------- paper cards ---------- */

body.demo-page .exam-section-grid { gap: 18px; }
body.demo-page .exam-card {
  border: 1px solid var(--border);
  border-radius: 16px;
  background-color: #ffffff;
  padding: 22px 20px;
  gap: 12px;
  box-shadow: 0 1px 2px rgba(13, 17, 23, 0.04);
  transition: transform 0.22s ease, box-shadow 0.28s ease, border-color 0.28s ease;
}
body.demo-page .exam-card:hover {
  transform: translateY(-3px);
  border-color: rgba(13, 17, 23, 0.16);
  box-shadow: 0 2px 6px rgba(13, 17, 23, 0.04), 0 18px 40px rgba(13, 17, 23, 0.10);
}
body.demo-page .exam-card h3 { font-size: 18.5px; font-weight: 650; letter-spacing: -0.018em; }
body.demo-page .exam-meta { font-size: 12.5px; }
/* Some papers have no subtitle line (GSRTC, for one), so their button would sit
   higher than the neighbouring cards'. Pushing it to the bottom of the card
   lines every action up across the row. */
body.demo-page .exam-card .btn { margin-top: auto; }
body.demo-page .exam-meta span { background-color: var(--surface); padding: 4px 11px; }

/* ---------- buttons ---------- */

body.demo-page .btn {
  border-radius: 999px;
  padding: 12px 24px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  transition: transform 0.16s ease, box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
body.demo-page .btn:hover { transform: translateY(-1px); }
body.demo-page .btn-primary {
  background-color: var(--accent);
  box-shadow: 0 1px 2px rgba(79, 70, 229, 0.24), 0 8px 22px rgba(79, 70, 229, 0.20);
}
body.demo-page .btn-primary:hover { background-color: var(--accent-hover); }
body.demo-page .btn-ghost {
  background-color: #ffffff;
  border-color: var(--border);
  color: var(--text-1);
  box-shadow: 0 1px 2px rgba(13, 17, 23, 0.04);
}

/* ---------- panels and the form ---------- */

body.demo-page .panel {
  border: 1px solid var(--border);
  border-radius: 18px;
  background-color: #ffffff;
  padding: 28px 26px;
  box-shadow: 0 2px 6px rgba(13, 17, 23, 0.04), 0 20px 48px rgba(13, 17, 23, 0.08);
}
body.demo-page .panel h3 { font-size: 20px; font-weight: 650; letter-spacing: -0.02em; }
body.demo-page .panel .hint { font-size: 14px; color: var(--text-3); }

body.demo-page .form-row input {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 13px 14px;
  font-size: 15.5px;
  color: var(--text-1);
}
body.demo-page .form-row input::placeholder { color: var(--text-4); }
body.demo-page .form-row input:focus {
  outline: none;
  border-color: rgba(79, 70, 229, 0.55);
  background-color: #ffffff;
  box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.12);
}
body.demo-page .form-row label { font-size: 13.5px; color: var(--text-2); }
body.demo-page .form-row .opt { color: var(--text-4); }

/* The consent block carries its own invalid state, added Sep 13 2026, and the
   toast is fixed at z-index 500. Neither is touched here beyond colour. */
body.demo-page .consent { font-size: 13.5px; color: var(--text-3); }

/* ---------- the closing card and footer ---------- */

body.demo-page .cta {
  border: 1px solid var(--border);
  border-radius: 18px;
  background-color: var(--surface);
  padding: 28px 26px;
  margin-top: 38px;
}
body.demo-page .cta h3 { font-size: 18px; font-weight: 650; color: var(--text-1); }
body.demo-page .cta p { font-size: 15px; color: var(--text-2); }

body.demo-page .demo-foot {
  margin-top: 46px;
  font-size: 13px;
  color: var(--text-4);
  line-height: 1.7;
}
body.demo-page .demo-foot a { color: var(--text-3); }

/* ---------- phones ---------- */

@media (max-width: 700px) {
  /* Same finding as the landing page: on a phone the copy is full width, so the
     field can never sit beside it. It becomes a texture rather than a pattern,
     while the mask above keeps the header and title area clean. */
  .wn-net { opacity: 0.2; }
  body.demo-page .demo-wrap { padding: 24px 18px 60px; }
  /* 0, not a negative inset: on a phone the wrap is as wide as the window, so
     anything outside it scrolls the page sideways. This was a real 20px
     overflow, caught by measuring rather than by eye. */
  body.demo-page .demo-wrap::before { height: 560px; left: 0; right: 0; }
  body.demo-page .panel { padding: 22px 18px; }
  body.demo-page .exam-card { padding: 18px 16px; }
  body.demo-page .btn { width: 100%; }
  body.demo-page .exam-card .btn { width: 100%; }
}

@media (max-width: 420px) {
  body.demo-page .demo-title { max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  body.demo-page .exam-card:hover,
  body.demo-page .btn:hover { transform: none; }
}

/* ---- Category chips above the exam list (Sep 18 2026) --------------------
   Horizontally scrollable so every chip stays reachable on a narrow phone
   without wrapping into the cards. The row is subtle by default and the
   active chip carries the brand fill, so the current view is obvious. */
.exam-chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 2px 14px;
  margin-bottom: 2px;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
.exam-chips::-webkit-scrollbar { display: none; }
.exam-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--text-2);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.exam-chip:hover:not(:disabled) { border-color: var(--brand); color: var(--text-1); }
.exam-chip:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.exam-chip.is-active { background: var(--brand); border-color: var(--brand); color: #fff; }
.exam-chip:disabled { opacity: .38; cursor: default; }
.exam-chip-count {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
}
.exam-chip.is-active .exam-chip-count { background: rgba(255, 255, 255, 0.22); }
@media (max-width: 560px) {
  .exam-chip { font-size: 12.5px; padding: 7px 12px; }
  .exam-chips { padding-bottom: 12px; }
}

/* ---- Chips: touch size, alignment and contrast (Sep 18 2026) -------------
   Measured on a 390px phone: the chips were 31px tall (below the 44px
   minimum tap target), sat 2px inside the content edge, and used a 12.5px
   face in a muted colour, so on first land the row read as decoration. */
.exam-chips-label {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-3);
  /* Breathing room between the intro lines and the chip row. Value set from a
     DevTools edit on iPhone Safari (Sep 19 2026). */
  padding-top: 15px;
  margin: 0 0 10px;
}
.exam-chips {
  padding: 0 0 16px;      /* no side padding: chips now line up with the cards */
  margin: 0 0 4px;
  gap: 9px;
}
.exam-chip {
  min-height: 44px;       /* iOS/Android minimum touch target */
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);   /* readable, not muted */
  background: rgba(255, 255, 255, 0.045);
}
.exam-chip.is-active {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);   /* the active one clearly leads */
}
.exam-chip-count {
  font-size: 12px;
  padding: 2px 8px;
}
.exam-section-title {
  font-size: 15px;        /* the heading must lead the cards, not trail them */
  letter-spacing: .02em;
  margin: 26px 0 16px;
}
@media (max-width: 560px) {
  .exam-chip { font-size: 13.5px; padding: 10px 15px; min-height: 44px; }
  .exam-chips { padding-bottom: 14px; }
  .exam-section-title { font-size: 14px; }
}

/* ---- Official resource link on a card (Sep 19 2026) ----------------------
   Points at free official practice material (the IELTS sample tests). Kept
   visually secondary to the Start button and underlined so it reads as a link
   rather than another action. */
.exam-resource {
  display: inline-block;
  margin: 2px 0 10px;
  font-size: 12.5px;
  color: var(--text-2);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.exam-resource:hover { color: var(--brand); }

/* ---- Intro list alignment (Sep 19 2026) ----------------------------------
   <ol class="steps"> carried the browser's default 40px padding-inline-start,
   so the whole "Pick a paper / Sit it on your phone / Get your score" block
   sat indented to the right of the BROWSE BY CATEGORY label, the chips and
   the section headings, which all start flush at the content edge. Markers are
   moved inside so they stay visible with the indent removed. */
.steps {
  padding-inline-start: 0;
  padding-left: 0;
  margin-left: 0;
  list-style-position: inside;
}
.steps li { padding-left: 0; }

/* ---- Intro lines flush with the column (Sep 19 2026) ---------------------
   The container was aligned but the TEXT was not: each <li> carried a tick
   icon rendered as a ::before marker, which pushed every line ~30px right of
   the BROWSE BY CATEGORY label, the chips, the section headings and the cards
   (all flush at the content edge). Measured: text started at x=48 against
   everything else at x=18 on a 390px viewport.

   The decorative tick is dropped so the text itself lands on the content edge.
   To bring the ticks back, restore them as a small inline prefix and accept
   that the text then starts after the glyph. */
.steps, .steps li { list-style: none; }
.steps li { padding-left: 0; margin-left: 0; text-indent: 0; }
.steps li::before, .steps li::marker { content: none; display: none; }

/* ---- Intro lines on the content edge, icons kept (Sep 19 2026) ----------
   Measured: every intro line's text started at x=48 while the BROWSE BY
   CATEGORY label, the chips, the section headings and the cards all start at
   x=18 on a 390px viewport.

   Cause: body.demo-page .steps li { padding-left: 30px } outranked a plain
   .steps li rule, so the earlier attempt did nothing. The tick is a ::before
   circle plus a ::after tick, not a list marker.

   Fix: keep both, but pull the indent in to the width the icon actually needs,
   so the text sits on the content edge to within 2px and the design is intact. */
body.demo-page .steps li { padding-left: 20px; }
body.demo-page .steps li::before { left: 0; }
body.demo-page .steps li::after { left: 5px; top: 10.5px; }

/* ---- Intro lines flush: drop the icon prefix (Sep 19 2026) --------------
   Measured sequence: the text began at x=48 (padding 30px from the rule
   body.demo-page .steps li), then x=38 with the padding pulled to 20px - still
   not on the content edge at x=18, because the 16px tick icon occupies the
   line's start. No indent value can put the text at x=18 while a glyph sits
   ahead of it.

   So the icon is dropped and the three lines are flush with the BROWSE BY
   CATEGORY label, the chips, the section headings and the cards - all x=18.
   To restore the tick, give the li a padding-left of 20px and reinstate the
   ::before circle and ::after tick; the text then starts after the glyph. */
body.demo-page .steps li { padding-left: 0; }
body.demo-page .steps li::before,
body.demo-page .steps li::after { content: none; }

/* ---- Category colour identity + a sticky filter bar (Sep 19 2026) --------
   Option B: each bucket carries its own colour so a category is recognisable
   at a glance, rather than every chip reading as inactive furniture.

   Follows Material Design 3's chip guidance: a leading dot is functional (it
   identifies the category, not decoration), the selected state must be
   unmistakable - here the dot becomes a tick - and a chip on a plain page uses
   a border rather than elevation, which is why the old active shadow is gone.

   Tones clear WCAG AA for white text in the filled state, and stay legible as
   a dot on a soft tint when idle. */
.exam-filterbar {
  position: sticky;
  top: 0;
  z-index: 6;              /* over the cards, under the modals and toasts */
  background: var(--bg);
  padding-top: 8px;
  margin-bottom: 2px;
}
.exam-chip {
  --tone: #475569;
  --tint: rgba(71, 85, 105, .10);
  background: var(--tint);
  border-color: rgba(15, 23, 42, .10);
  color: var(--text-1);
}
.exam-chip[data-chip="all"]     { --tone: #0f172a; --tint: rgba(15, 23, 42, .07); }
.exam-chip[data-chip="non_it"]  { --tone: #b45309; --tint: rgba(180, 83, 9, .11); }
.exam-chip[data-chip="it"]      { --tone: #1d4ed8; --tint: rgba(29, 78, 216, .10); }
.exam-chip[data-chip="english"] { --tone: #047857; --tint: rgba(4, 120, 87, .11); }
.exam-chip::before {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--tone);
}
.exam-chip.is-active {
  background: var(--tone);
  border-color: var(--tone);
  color: #fff;
  box-shadow: none;
}
.exam-chip.is-active::before {
  content: '\2713';
  width: auto;
  height: auto;
  background: none;
  font-size: 12px;
  line-height: 1;
}
.exam-chip:hover:not(:disabled):not(.is-active) { border-color: var(--tone); }
.exam-chip:disabled { opacity: .45; }
