/* Zylif — shared UI added on top of the page stylesheets.
   Skip link, accessible quiz controls, progress tracking, search overlay. */

/* ---------- utilities ---------- */
.zy-sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ---------- skip link ---------- */
.zy-skip{position:absolute;left:-9999px;top:0;z-index:200;
  background:var(--accent,#b6ff39);color:#000;font-family:var(--mono,monospace);
  font-size:.8rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  padding:.85rem 1.3rem;border-radius:0 0 10px 0;text-decoration:none}
.zy-skip:focus{left:0}

/* ---------- quiz: real buttons, not clickable <li> ---------- */
.quiz-options{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.45rem}
.quiz-options li{margin:0;padding:0;border:0;background:none;max-width:none}
.quiz-opt{display:flex;align-items:center;gap:.6rem;width:100%;text-align:left;
  font-family:var(--body,Georgia,serif);font-size:.95rem;line-height:1.45;
  color:var(--ink-dim,#9a9588);background:none;
  padding:.62rem .8rem;min-height:44px;border:1px solid var(--rule,rgba(243,238,229,.12));
  border-radius:7px;cursor:pointer;
  transition:background var(--t-fast,220ms) var(--ease,ease),
             border-color var(--t-fast,220ms) var(--ease,ease),
             color var(--t-fast,220ms) var(--ease,ease)}
.quiz-opt:hover:not(:disabled){background:rgba(255,255,255,.05);
  border-color:var(--rule-strong,rgba(243,238,229,.26));color:var(--ink,#f3eee5)}
.quiz-opt:disabled{cursor:default}
.quiz-opt.correct{background:rgba(182,255,57,.1);border-color:rgba(182,255,57,.5);
  color:var(--accent,#b6ff39)}
.quiz-opt.wrong{background:rgba(255,120,120,.09);border-color:rgba(255,120,120,.5);color:#ff9b9b}
/* the shape carries the meaning too, not just the hue */
.quiz-mark{margin-left:auto;flex-shrink:0;font-family:var(--mono,monospace);
  font-size:1rem;font-weight:700;line-height:1}
.quiz-feedback{font-family:var(--mono,monospace);font-size:.78rem;letter-spacing:.06em;
  margin:.7rem 0 0;padding:.5rem .7rem;border-radius:6px;border:1px solid transparent}
.quiz-feedback.is-correct{color:var(--accent,#b6ff39);border-color:rgba(182,255,57,.35);
  background:rgba(182,255,57,.07)}
.quiz-feedback.is-wrong{color:#ff9b9b;border-color:rgba(255,120,120,.35);
  background:rgba(255,120,120,.06)}
html[data-contrast="high"] .quiz-opt.correct{background:#000;color:#e0ff7a;border-color:#e0ff7a}
html[data-contrast="high"] .quiz-opt.wrong{background:#000;color:#ffb3b3;border-color:#ffb3b3}

/* ---------- reading-preferences radios ---------- */
.a11y-options [role="radio"]{cursor:pointer;min-height:34px}
.a11y-options [role="radio"][aria-checked="true"]{background:var(--accent,#b6ff39);color:#000;
  border-color:var(--accent,#b6ff39);font-weight:700}

/* ---------- minimum hit areas (WCAG 2.2 target size) ---------- */
#a11y-close{min-width:32px;min-height:32px;display:inline-flex;align-items:center;
  justify-content:center;margin-left:auto;border-radius:8px}
#a11y-close:hover{background:rgba(255,255,255,.08)}
.topbar-breadcrumb a{display:inline-flex;align-items:center;min-height:32px;padding:0 .15rem}

/* ---------- completion ---------- */
.zy-complete{display:flex;justify-content:center;margin:2.5rem 0 1rem}
.zy-complete-btn{display:inline-flex;align-items:center;gap:.6rem;
  font-family:var(--mono,monospace);font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-dim,#9a9588);background:none;
  padding:.8rem 1.35rem;min-height:44px;
  border:1px solid var(--rule-strong,rgba(243,238,229,.26));border-radius:999px;cursor:pointer;
  transition:color .2s,border-color .2s,background .2s}
.zy-complete-btn:hover{color:var(--ink,#f3eee5);border-color:var(--ink,#f3eee5);
  background:rgba(255,255,255,.05)}
.zy-complete-btn.is-done{color:#000;background:var(--tc,var(--accent,#b6ff39));
  border-color:var(--tc,var(--accent,#b6ff39));font-weight:700}
.zy-tick{font-size:.95rem;line-height:1}

.zy-done-mark{margin-left:auto;padding-left:.4rem;color:var(--tc,var(--accent,#b6ff39));
  font-family:var(--mono,monospace);font-size:.8rem;flex-shrink:0}
a.zy-done .sidebar-code{opacity:.6}

/* ---------- track progress strip ---------- */
.zy-track-progress{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;
  margin:0 0 2rem;padding:.85rem 1.1rem;
  border:1px solid var(--rule,rgba(243,238,229,.12));border-radius:10px;
  background:var(--bg-elev,#1c1109)}
.zy-track-progress-count{font-family:var(--mono,monospace);font-size:.72rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-dim,#9a9588)}
.zy-meter{flex:1 1 120px;min-width:100px;height:6px;border-radius:999px;
  background:rgba(255,255,255,.1);overflow:hidden;display:block}
.zy-meter>span{display:block;height:100%;border-radius:999px;
  background:var(--tc,var(--accent,#b6ff39))}
.zy-resume{font-family:var(--mono,monospace);font-size:.72rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--tc,var(--accent,#b6ff39));text-decoration:none;
  padding:.5rem .3rem;min-height:32px;display:inline-flex;align-items:center}
.zy-resume:hover{text-decoration:underline}

/* ---------- resume banner ---------- */
.zy-resume-banner{position:fixed;right:1rem;bottom:1rem;z-index:70;
  display:flex;flex-direction:column;gap:.15rem;
  padding:.8rem 1.1rem;border-radius:12px;text-decoration:none;
  background:var(--bg-elev,#1c1109);border:1px solid var(--rule-strong,rgba(243,238,229,.26));
  box-shadow:0 10px 30px -12px rgba(0,0,0,.8);max-width:min(78vw,20rem)}
.zy-resume-banner:hover{border-color:var(--accent,#b6ff39)}
.zy-resume-label{font-family:var(--mono,monospace);font-size:.62rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-dim,#9a9588)}
.zy-resume-mod{font-family:var(--serif,serif);font-size:1.05rem;font-weight:700;
  color:var(--ink,#f3eee5)}
.zy-resume-count{font-family:var(--mono,monospace);font-size:.62rem;letter-spacing:.1em;
  color:var(--accent,#b6ff39)}
@media (max-width:900px){.zy-resume-banner{left:1rem;right:1rem;bottom:.75rem;max-width:none}}

/* ==========================================================================
   DIAGRAMS (.zfig) — make the 149 figures obey the reader's settings
   --------------------------------------------------------------------------
   Figure text is positioned at absolute coordinates, so its font has to be
   deterministic: Inter is self-hosted and pinned. Any figure that does not
   name a font inherits from here rather than falling through to the body
   serif.
   ========================================================================== */
.zfig svg{font-family:Inter,Arial,Helvetica,sans-serif}

/* "Readable" must reach inside the figures too, not just the prose. */
html[data-font="dyslexic"] .zfig svg,
html[data-font="dyslexic"] .zfig svg text{
  font-family:"Atkinson Hyperlegible",Inter,Arial,sans-serif!important;
}

/* Figures scale with the text-size setting. Their internal type is in user
   units, so the whole frame has to grow — otherwise XXL body text sits next to
   unchanged 9px diagram labels. max-width in rem does exactly that. */
.zfig{max-width:44rem;margin-inline:auto}
.zfig-frame{overflow-x:auto}
.zfig svg{width:100%;height:auto;display:block}

/* High contrast: the figures carry baked-in dark cards that would otherwise
   float as grey slabs on a pure-black page. Give them a visible edge and let
   the card read as deliberate. */
html[data-contrast="high"] .zfig-frame{
  border-width:3px;border-style:solid;border-color:#fff;border-radius:10px;
}
html[data-contrast="high"] .zfig figure{margin-inline:0}

/* ---------- shared footer (was on 3 of 56 pages) ---------- */
.zy-footer{border-top:1px solid var(--rule,rgba(243,238,229,.12));
  margin-top:5rem;padding:3rem var(--gutter,clamp(20px,4vw,56px)) 2rem;
  background:var(--bg,#120a05);position:relative;z-index:2}
.zy-footer-inner{max-width:1180px;margin:0 auto;display:grid;gap:2.5rem;
  grid-template-columns:minmax(14rem,2fr) repeat(3,minmax(8rem,1fr))}
.zy-footer-brand p{margin:.7rem 0 0;max-width:34ch;font-family:var(--body,Georgia,serif);
  font-size:.95rem;line-height:1.6;color:var(--ink-dim,#9a9588)}
.zy-footer-word{font-family:var(--serif,serif);font-weight:800;font-style:italic;
  font-size:1.25rem;letter-spacing:-.02em;color:var(--ink,#f3eee5)}
.zy-footer-col{display:flex;flex-direction:column;gap:.15rem}
.zy-footer-col h2{font-family:var(--mono,monospace);font-size:.68rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-faint,#8b8578);margin:0 0 .6rem;font-weight:500}
.zy-footer-col a{font-family:var(--body,Georgia,serif);font-size:.95rem;
  color:var(--ink-dim,#9a9588);text-decoration:none;
  padding:.4rem 0;min-height:32px;display:inline-flex;align-items:center}
.zy-footer-col a:hover{color:var(--ink,#f3eee5);text-decoration:underline}
.zy-footer-base{max-width:1180px;margin:2.5rem auto 0;padding-top:1.4rem;
  border-top:1px solid var(--rule,rgba(243,238,229,.12));
  display:flex;flex-wrap:wrap;gap:.6rem 1.5rem;justify-content:space-between;
  font-family:var(--mono,monospace);font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-faint,#8b8578)}
@media (max-width:860px){
  .zy-footer-inner{grid-template-columns:1fr 1fr}
  .zy-footer-brand{grid-column:1/-1}
}
@media (max-width:560px){.zy-footer-inner{grid-template-columns:1fr}}
/* modules put the footer below the sidebar/prose grid, not inside it */
.page-layout+.zy-footer{margin-top:4rem}

/* Chrome action slot created on pages that ship neither .topbar-right nor
   .nav-right (the /courses/ hub and 404). */
.zy-chrome-actions{display:flex;align-items:center;gap:.6rem;margin-left:auto}
.zy-chrome-floating{position:fixed;top:1rem;right:1rem;z-index:65;
  background:var(--bg-elev,#1c1109);padding:.3rem;border-radius:999px;
  border:1px solid var(--rule,rgba(243,238,229,.12))}

/* ---------- search ---------- */
.zy-search-btn{display:inline-flex;align-items:center;gap:.45rem;
  font-family:var(--mono,monospace);font-size:.71rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-dim,#9a9588);background:none;
  padding:.45rem .85rem;min-height:36px;
  border:1px solid var(--rule,rgba(243,238,229,.12));border-radius:999px;cursor:pointer;
  transition:color .2s,border-color .2s}
.zy-search-btn:hover{color:var(--ink,#f3eee5);border-color:var(--rule-strong,rgba(243,238,229,.26))}
.zy-search-btn svg{width:.85rem;height:.85rem;flex-shrink:0}
@media (max-width:560px){.zy-search-btn-text{display:none}.zy-search-btn{padding:.45rem .6rem}}

.zy-search{position:fixed;inset:0;z-index:300;background:rgba(6,3,1,.72);
  backdrop-filter:blur(6px);display:flex;align-items:flex-start;justify-content:center;
  padding:min(12vh,7rem) 1rem 2rem}
.zy-search[hidden]{display:none}
body.zy-search-open{overflow:hidden}
.zy-search-panel{width:min(40rem,100%);max-height:80vh;display:flex;flex-direction:column;
  background:var(--bg-elev,#1c1109);border:1px solid var(--rule-strong,rgba(243,238,229,.26));
  border-radius:14px;overflow:hidden;box-shadow:0 30px 80px -20px rgba(0,0,0,.9)}
.zy-search-head{display:flex;align-items:center;gap:.7rem;padding:.9rem 1rem;
  border-bottom:1px solid var(--rule,rgba(243,238,229,.12))}
.zy-search-ico{width:1.05rem;height:1.05rem;color:var(--ink-dim,#9a9588);flex-shrink:0}
.zy-search-input{flex:1;background:none;border:0;outline:none;color:var(--ink,#f3eee5);
  font-family:var(--body,Georgia,serif);font-size:1.05rem;min-width:0}
.zy-search-input::placeholder{color:var(--ink-faint,#8b8578)}
.zy-search-close{background:none;border:0;color:var(--ink-dim,#9a9588);font-size:1.5rem;
  line-height:1;cursor:pointer;padding:.2rem .4rem;min-width:36px;min-height:36px}
.zy-search-close:hover{color:var(--ink,#f3eee5)}
.zy-search-status{margin:0;padding:.6rem 1rem;font-family:var(--mono,monospace);
  font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint,#8b8578)}
.zy-search-results{list-style:none;margin:0;padding:0 .5rem .5rem;overflow-y:auto;flex:1}
.zy-search-results li{margin:0}
.zy-search-results a{display:flex;align-items:center;gap:.85rem;padding:.7rem .8rem;
  min-height:44px;border-radius:8px;text-decoration:none;color:var(--ink-dim,#9a9588)}
.zy-search-results a:hover,.zy-search-results a:focus,
.zy-search-results a[aria-selected="true"]{background:rgba(255,255,255,.07);
  color:var(--ink,#f3eee5);outline:none}
.zy-search-results a[aria-selected="true"]{box-shadow:inset 0 0 0 1px var(--accent,#b6ff39)}
.zy-hit-code{font-family:var(--mono,monospace);font-size:.7rem;letter-spacing:.1em;
  color:var(--accent,#b6ff39);min-width:2.8rem;flex-shrink:0}
.zy-hit-main{display:flex;flex-direction:column;gap:.1rem;min-width:0}
.zy-hit-title{font-family:var(--body,Georgia,serif);font-size:.98rem;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zy-hit-track{font-family:var(--mono,monospace);font-size:.64rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-faint,#8b8578)}
.zy-search-hint{margin:0;padding:.6rem 1rem;border-top:1px solid var(--rule,rgba(243,238,229,.12));
  font-family:var(--mono,monospace);font-size:.64rem;letter-spacing:.08em;
  color:var(--ink-faint,#8b8578);text-align:center}
@media (max-width:560px){.zy-search-hint{display:none}}

/* Motion preferences apply to everything added here too. */
html[data-motion="off"] .zy-search,html[data-motion="off"] .zy-meter>span{transition:none!important}

/* ==========================================================================
   MOTION — corrective layer
   --------------------------------------------------------------------------
   The base sheets clamp EVERY animation to `animation-duration:1.2s!important`
   under "reduced". For the two hero marquees (38s and 65s) that is a 32x and
   54x SPEED-UP: the setting meant to protect people with vestibular disorders
   was the thing making the page strobe.

   It cannot simply be replaced with `animation:none`, because the hero title
   and subtitle sit at `opacity:0` and depend on `animation ... forwards` to
   become visible. Killing all animation would blank the hero.

   So: looping decoration stops dead; one-shot entrances keep their (already
   short) duration. `.zy-noloop` is set by app.js for any looping animation
   added later, so this does not silently regress again.
   ========================================================================== */
html[data-motion="reduced"] .ticker-track,
html[data-motion="reduced"] .ticker-tag::before,
html[data-motion="reduced"] .scroll-cue::after,
html[data-motion="reduced"] .zy-noloop,
html[data-motion="reduced"] .zy-noloop::before,
html[data-motion="reduced"] .zy-noloop::after,
html[data-motion="off"] .ticker-track,
html[data-motion="off"] .ticker-tag::before,
html[data-motion="off"] .scroll-cue::after,
html[data-motion="off"] .zy-noloop,
html[data-motion="off"] .zy-noloop::before,
html[data-motion="off"] .zy-noloop::after{
  animation:none!important;
}

/* Entrances stay finite and brief; never let the clamp lengthen a loop. */
html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after{
  animation-iteration-count:1!important;
}

/* Respect the OS setting even before the reader opens the panel. */
@media (prefers-reduced-motion: reduce){
  html:not([data-motion="on"]) .ticker-track,
  html:not([data-motion="on"]) .ticker-tag::before,
  html:not([data-motion="on"]) .scroll-cue::after{
    animation:none!important;
  }
}

/* ==========================================================================
   POINTER — large cursor
   Rebuilt: 32x32 (browsers ignore oversized cursor images), properly
   percent-encoded (the old `;utf8,<svg ...>` form is not a valid data URI),
   and applied to every element rather than just body/a/button, so inputs and
   nested nodes stop falling back to the system arrow.
   ========================================================================== */
html[data-pointer="large"],
html[data-pointer="large"] body,
html[data-pointer="large"] *{
  cursor:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2732%27%20height%3D%2732%27%20viewBox%3D%270%200%2040%2040%27%3E%3Cpath%20d%3D%27M3%203%20L3%2032%20L11%2024%20L17%2038%20L22%2036%20L16%2022%20L26%2022%20Z%27%20fill%3D%27%23ffffff%27%20stroke%3D%27%23000000%27%20stroke-width%3D%272.5%27%20stroke-linejoin%3D%27round%27%2F%3E%3C%2Fsvg%3E") 2 2,auto!important;
}
html[data-pointer="large"] a,
html[data-pointer="large"] button,
html[data-pointer="large"] [role="button"],
html[data-pointer="large"] [role="radio"],
html[data-pointer="large"] summary,
html[data-pointer="large"] label,
html[data-pointer="large"] select{
  cursor:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2732%27%20height%3D%2732%27%20viewBox%3D%270%200%2040%2040%27%3E%3Cpath%20d%3D%27M14%204%20L14%2022%20L9%2022%20L18%2036%20L26%2022%20L22%2022%20L22%204%20Z%27%20fill%3D%27%23b6ff39%27%20stroke%3D%27%23000000%27%20stroke-width%3D%272.5%27%20stroke-linejoin%3D%27round%27%2F%3E%3C%2Fsvg%3E") 14 3,pointer!important;
}
html[data-pointer="large"] input:not([type="button"]):not([type="submit"]):not([type="checkbox"]):not([type="radio"]),
html[data-pointer="large"] textarea{
  cursor:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2732%27%20height%3D%2732%27%20viewBox%3D%270%200%2032%2032%27%3E%3Cpath%20d%3D%27M12%204%20h8%20M16%204%20v24%20M12%2028%20h8%27%20fill%3D%27none%27%20stroke%3D%27%23000000%27%20stroke-width%3D%276%27%2F%3E%3Cpath%20d%3D%27M12%204%20h8%20M16%204%20v24%20M12%2028%20h8%27%20fill%3D%27none%27%20stroke%3D%27%23ffffff%27%20stroke-width%3D%273%27%2F%3E%3C%2Fsvg%3E") 16 16,text!important;
}

/* ---------- settings trigger (one affordance on all 56 pages) ---------- */
.a11y-fab{position:fixed;right:18px;bottom:18px;z-index:70;width:46px;height:46px;
  border-radius:50%;background:var(--bg-elev,#1c1109);
  border:1px solid var(--rule-strong,rgba(243,238,229,.26));color:var(--ink,#f3eee5);
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  box-shadow:0 6px 22px -8px rgba(0,0,0,.7);
  transition:border-color .22s ease,transform .22s ease}
.a11y-fab:hover{border-color:var(--accent,#b6ff39);transform:translateY(-1px)}
.a11y-fab svg{width:22px;height:22px}
/* The resume banner also sits bottom-right; lift the fab above it when both
   are on screen rather than letting them overlap. */
body:has(.zy-resume-banner) .a11y-fab{bottom:6.5rem}
@media (max-width:900px){
  .a11y-fab{right:12px;bottom:12px}
  body:has(.zy-resume-banner) .a11y-fab{bottom:7.5rem}
}
