/* ===========================================================================
   Worldwide K9 Academy - Online School
   Design system lifted from worldwidek9academy.com so the school reads as the
   same product: Hanken Grotesk, cream paper, navy, green accent, pill buttons.
   =========================================================================== */

@font-face{
  font-family:'Hanken Grotesk';font-style:normal;font-display:swap;font-weight:100 900;
  src:url(assets/fonts/hanken-grotesk-latin-wght-normal.woff2) format('woff2-variations');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Hanken Grotesk';font-style:normal;font-display:swap;font-weight:100 900;
  src:url(assets/fonts/hanken-grotesk-latin-ext-wght-normal.woff2) format('woff2-variations');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root{
  --navy:#102444;
  --navy-2:#1b3563;
  --navy-ink:#0a182f;
  --green:#6bb94b;
  --green-d:#56a138;
  --green-deep:#3f7e2a;
  --paper:#f6f3ec;
  --paper-2:#efeadd;
  --card:#ffffff;
  --ink:#172033;
  --muted:#5c6779;
  --line:#e6e0d2;
  --line-soft:#efeadd;
  --line-cool:#dde4f0;
  --shadow-sm:0 2px 8px rgba(16,36,68,.06);
  --shadow:0 18px 44px -22px rgba(16,36,68,.32);
  --shadow-lg:0 40px 80px -36px rgba(16,36,68,.45);
  --sans:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,system-ui,sans-serif;
  --serif:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,system-ui,sans-serif;
  --maxw:1200px;
}

/* Stop iOS inflating text of its own accord.

   When a page's layout width changes, iOS decides some text is now too small
   to read and scales it up on its own. Rotating the phone is the usual
   trigger, which is why the header suddenly grew after a rotation and stayed
   that way. It is not zoom, so the scale lock does not touch it and double
   tapping does not undo it: the font sizes themselves have been rewritten.

   100% means "use the size I asked for". Text can still be scaled by the
   reader through iOS accessibility settings, which is the control that should
   be doing this. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}

*{box-sizing:border-box;margin:0;padding:0}
[hidden]{display:none!important}
body{
  font-family:var(--sans);color:var(--ink);background:var(--paper);
  line-height:1.6;-webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
button,input,textarea,select{font-family:inherit}
:focus-visible{outline:2px solid var(--green);outline-offset:3px;border-radius:4px}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 28px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.eyebrow{
  display:inline-flex;align-items:center;gap:9px;
  font-size:.74rem;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;color:var(--green-deep);
}
.eyebrow::before{content:"";width:26px;height:2px;background:var(--green);border-radius:2px}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-family:var(--sans);font-weight:700;font-size:.95rem;
  padding:14px 26px;border-radius:999px;cursor:pointer;border:0;
  transition:transform .18s ease,box-shadow .25s ease,background .2s ease,color .2s ease;
  letter-spacing:.01em;white-space:nowrap;text-align:center;
}
.btn-green{background:var(--green);color:#0c2208;box-shadow:0 12px 24px -10px rgba(86,161,56,.6)}
.btn-green:hover{transform:translateY(-2px);background:var(--green-d);box-shadow:0 18px 30px -12px rgba(86,161,56,.7)}
.btn-navy{background:var(--navy);color:#fff}
.btn-navy:hover{transform:translateY(-2px);background:var(--navy-2)}
.btn-ghost{background:transparent;color:var(--navy);border:1.5px solid var(--line)}
.btn-ghost:hover{border-color:var(--navy);transform:translateY(-2px)}
.btn-outline-navy{background:transparent;color:var(--navy);border:1.6px solid var(--navy);padding:10px 18px;font-size:.87rem}
.btn-outline-navy:hover{background:var(--navy);color:#fff;transform:translateY(-2px)}
.btn-ghost-l{background:transparent;color:#fff;border:1.5px solid rgba(255,255,255,.4)}
.btn-ghost-l:hover{border-color:#fff;background:rgba(255,255,255,.1);transform:translateY(-2px)}
.btn-block{width:100%}
.btn[disabled]{opacity:.5;cursor:not-allowed;transform:none!important;box-shadow:none}

/* ---------- header (matches the main site nav) ---------- */
.wk9-nav{
  position:sticky;top:0;z-index:9999;
  background:rgba(246,243,236,.94);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-bottom:1px solid rgba(16,36,68,.12);

  /* The notch. In a browser this is always zero, because the browser's own
     chrome already sits between the page and the hardware. Inside the app the
     page owns the whole screen, so without this the nav renders underneath
     the status bar and the clock is printed over the logo.

     Padding the bar rather than moving it keeps the blurred background
     running all the way to the top edge, so what sits behind the clock is the
     same frosted panel as the rest of the nav instead of a strip of whatever
     the page happens to have scrolled to. */
  padding-top:env(safe-area-inset-top, 0px);
}
.wk9-nav-in{
  max-width:var(--maxw);margin:0 auto;height:78px;
  /* Left and right matter in landscape, where the notch moves to one side. */
  padding:0 max(28px, env(safe-area-inset-left, 0px)) 0 max(28px, env(safe-area-inset-right, 0px));
  display:flex;align-items:center;justify-content:space-between;gap:20px;
}
.wk9-logo{display:flex;align-items:center;flex:none}
.wk9-logo img{height:52px;width:auto}
.wk9-links{display:flex;align-items:center;gap:30px;list-style:none}
.wk9-links a{position:relative;color:var(--navy);font-size:.95rem;font-weight:600;padding:6px 0}
.wk9-links a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:var(--green);transform:scaleX(0);transform-origin:left;transition:transform .2s ease;
}
.wk9-links a:hover::after,.wk9-links a.wk9-on::after{transform:scaleX(1)}
.wk9-right{display:flex;align-items:center;gap:14px;flex:none}
.wk9-who{color:var(--muted);font-size:.88rem;font-weight:600;max-width:16rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wk9-out{
  background:transparent;color:var(--navy);border:1.5px solid rgba(16,36,68,.2);
  font-size:.88rem;font-weight:700;padding:9px 20px;border-radius:999px;cursor:pointer;
  transition:border-color .18s ease,background .18s ease,transform .18s ease;white-space:nowrap;
}
.wk9-out:hover{border-color:var(--navy);transform:translateY(-2px)}
.wk9-burger{display:none;background:none;border:0;cursor:pointer;padding:10px;flex-direction:column;gap:5px}
.wk9-burger span{display:block;width:24px;height:2px;background:var(--navy);border-radius:2px;transition:transform .25s ease,opacity .2s ease}
.wk9-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.wk9-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.wk9-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

@media(max-width:900px){
  /* Repeats the inset padding, because this rule would otherwise reset the
     one above back to a flat 18px and put the burger under the notch in
     landscape. */
  .wk9-nav-in{
    height:66px;
    padding:0 max(18px, env(safe-area-inset-right, 0px)) 0 max(18px, env(safe-area-inset-left, 0px));
  }
  .wk9-logo img{height:42px}
  .wk9-burger{display:flex}
  .wk9-links,.wk9-who{display:none}
  .wk9-nav[data-open="true"] .wk9-links{
    display:flex;flex-direction:column;align-items:stretch;gap:0;
    position:absolute;left:0;right:0;background:var(--paper);
    border-bottom:1px solid var(--line);padding:8px 22px 22px;
    box-shadow:0 20px 34px -22px rgba(16,36,68,.4);z-index:10000;

    /* An absolutely positioned child is placed from the padding box, which now
       starts above the notch. A flat 66px would therefore open the menu
       overlapping the nav bar by exactly the height of the inset. */
    top:calc(66px + env(safe-area-inset-top, 0px));
  }
  .wk9-nav[data-open="true"] .wk9-links li{text-align:right}
  .wk9-nav[data-open="true"] .wk9-links a{display:block;text-align:right;padding:16px 0;font-size:1.14rem}
  .wk9-nav[data-open="true"] .wk9-links a::after{display:none}
}

/* ---------- footer (matches the main site) ---------- */
/* The bottom inset is the home indicator, the thin bar iPhones draw instead
   of a home button. Without this the footer's last line sits behind it. */
.wk9-foot{
  background:var(--paper);border-top:1px solid var(--line);margin-top:auto;
  padding:34px 0 calc(26px + env(safe-area-inset-bottom, 0px));
}
.wk9-foot-in{max-width:var(--maxw);margin:0 auto;padding:0 28px}
.wk9-foot-row{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:20px}
.wk9-foot-logo{justify-self:start}
.wk9-foot-logo img{width:158px;height:auto}
.wk9-foot-soc{justify-self:center;display:flex;align-items:center;gap:20px}
.wk9-foot-soc a{display:block;width:36px;height:36px;transition:transform .18s ease}
.wk9-foot-soc a:hover{transform:translateY(-3px)}
.wk9-foot-soc img{width:100%;height:100%}
.wk9-foot-spacer{justify-self:end}
.wk9-foot-legal{
  margin-top:26px;padding-top:18px;border-top:1px solid var(--line-soft);
  display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  font-size:.79rem;color:var(--muted);
}
.wk9-foot-legal a{color:var(--green-deep);font-weight:600}
.wk9-foot-legal a:hover{text-decoration:underline}
.wk9-foot-legal .sep{opacity:.45;margin:0 8px}
@media(max-width:760px){
  .wk9-foot{padding:28px 0 22px}
  .wk9-foot-in{padding:0 18px}
  .wk9-foot-row{grid-template-columns:1fr;justify-items:center;gap:18px;text-align:center}
  .wk9-foot-logo{justify-self:center}
  .wk9-foot-logo img{width:146px}
  .wk9-foot-spacer{display:none}
  .wk9-foot-legal{justify-content:center;text-align:center;flex-direction:column;gap:8px;margin-top:20px}
}

/* ---------- forms ---------- */
.field-label{display:block;font-size:.72rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin-bottom:8px}
.field{
  width:100%;background:#fff;border:1.5px solid var(--line);border-radius:12px;
  padding:14px 16px;color:var(--ink);font-size:1rem;
  transition:border-color .18s ease,box-shadow .18s ease;
}
.field::placeholder{color:#9aa4b4}
.field:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 4px rgba(107,185,75,.16)}
textarea.field{resize:vertical;line-height:1.65}

.notice{border-radius:12px;padding:13px 16px;font-size:.92rem;line-height:1.55;margin-bottom:20px}
.notice-error{background:#fdf1ef;border:1px solid #f0c8c0;color:#96341f}
.notice-ok{background:#f0f8ec;border:1px solid #c9e6b9;color:var(--green-deep)}

/* ---------- login gateway ---------- */
.gate-page{
  min-height:var(--app-vh, 100dvh);display:flex;flex-direction:column;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(107,185,75,.13), transparent 55%),
    radial-gradient(90% 80% at 50% 100%, rgba(27,53,99,.06), transparent 60%),
    var(--paper);
}
/* The sign in page has no nav bar to hide behind, so the insets are added
   straight to its padding. This is the page where the problem showed first:
   the logo is the topmost thing on screen and went under the notch. */
.gate-main{
  flex:1;display:flex;align-items:center;justify-content:center;
  padding:calc(44px + env(safe-area-inset-top, 0px))
          max(20px, env(safe-area-inset-right, 0px))
          calc(56px + env(safe-area-inset-bottom, 0px))
          max(20px, env(safe-area-inset-left, 0px));
}
.gate-inner{width:100%;max-width:452px}
.gate-art{position:relative;width:150px;margin:0 auto 22px}
.gate-art::before{content:"";display:block;padding-top:100%}
.gate-art .rings{position:absolute;inset:0;border-radius:50%;border:1px dashed rgba(27,53,99,.22);animation:gate-spin 60s linear infinite}
.gate-art .rings.r2{inset:11%;border-style:solid;border-color:rgba(107,185,75,.28);animation-duration:42s;animation-direction:reverse}
.gate-art img{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:74%;height:74%;object-fit:contain;filter:drop-shadow(0 18px 30px rgba(16,36,68,.24))}
@keyframes gate-spin{to{transform:rotate(360deg)}}
.gate-head{text-align:center;margin-bottom:26px}
.gate-head h1{font-family:var(--serif);font-weight:600;font-size:clamp(2rem,4.4vw,2.6rem);line-height:1.06;letter-spacing:-.015em;color:var(--navy);margin-top:14px}
.gate-head p{color:var(--muted);margin-top:10px;font-size:1rem}
.gate-card{background:var(--card);border:1px solid var(--line);border-radius:22px;box-shadow:var(--shadow);padding:30px 28px 26px}
.tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px;background:var(--paper-2);border-radius:999px;padding:5px;margin-bottom:24px}
.tab{
  border:0;background:transparent;border-radius:999px;padding:11px 8px;cursor:pointer;
  font-size:.9rem;font-weight:700;color:var(--muted);transition:background .18s ease,color .18s ease;
}
.tab:hover{color:var(--navy)}
.tab[aria-selected="true"]{background:var(--navy);color:#fff}
.stack{display:grid;gap:16px}
.gate-alt{text-align:center;font-size:.92rem;color:var(--muted);margin-top:4px}
.linkish{background:none;border:0;padding:0;cursor:pointer;color:var(--green-deep);font-weight:700;font-size:.92rem;text-decoration:underline;text-underline-offset:3px}
.linkish:hover{color:var(--green-d)}
.gate-foot{margin-top:22px;padding-top:18px;border-top:1px solid var(--line-soft);text-align:center;font-size:.85rem;color:var(--muted)}
.gate-foot a{color:var(--green-deep);font-weight:600}
.gate-back{text-align:center;margin-top:22px;font-size:.85rem;color:var(--muted)}
.gate-back a{font-weight:600}
.gate-back a:hover{color:var(--green-deep)}
@media(max-width:560px){.gate-card{padding:24px 20px 22px;border-radius:18px}}

/* ---------- shared page shell ---------- */
.page{min-height:var(--app-vh, 100dvh);display:flex;flex-direction:column}
.page-main{flex:1}
.boot{
  position:fixed;inset:0;z-index:12000;display:grid;place-items:center;
  background:var(--paper);text-align:center;
  padding:env(safe-area-inset-top, 0px) 0 env(safe-area-inset-bottom, 0px);
}
.boot p{margin-top:14px;font-size:.74rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.boot img{width:64px;height:64px;object-fit:contain;margin:0 auto}

/* ---------- dashboard ---------- */
.hub-head{padding:52px 0 34px}
.hub-head h1{font-family:var(--serif);font-weight:600;font-size:clamp(2.1rem,4.2vw,3rem);line-height:1.06;letter-spacing:-.015em;color:var(--navy);margin:16px 0 12px}
.hub-head p.lede{color:var(--muted);font-size:1.06rem;max-width:56ch}

.resume{
  margin-top:30px;border-radius:20px;padding:24px 26px;color:#fff;
  display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;
  box-shadow:var(--shadow);
  background:
    radial-gradient(140% 120% at 108% 110%, rgba(107,185,75,.4), transparent 58%),
    linear-gradient(155deg,var(--navy-2),var(--navy));
}
.resume .tag{
  display:inline-flex;align-items:center;background:var(--green);color:#0c2208;
  font-size:.66rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  padding:6px 13px;border-radius:999px;margin-bottom:11px;
}
.resume h2{font-family:var(--serif);font-weight:600;font-size:1.5rem;line-height:1.15}
.resume p{color:#bccbe0;font-size:.93rem;margin-top:4px}

.billing{
  display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;
  background:var(--card);border:1px solid var(--line);border-radius:16px;
  padding:18px 22px;margin-bottom:22px;box-shadow:var(--shadow-sm);
}
.billing .k{font-size:.66rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--green-deep);margin-bottom:5px}
.billing .d{font-size:.94rem;color:var(--muted)}
.billing-acts{display:flex;gap:10px;flex-wrap:wrap}

.pkg-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;padding-bottom:22px}
@media(max-width:1000px){.pkg-grid{grid-template-columns:1fr 1fr}}
@media(max-width:640px){.pkg-grid{grid-template-columns:1fr}}

.pkg{
  position:relative;overflow:hidden;border-radius:18px;padding:24px 24px 22px 28px;
  display:flex;flex-direction:column;
  background:
    radial-gradient(120% 95% at 100% 100%, rgba(107,185,75,.14), transparent 56%),
    linear-gradient(152deg,#eef3fb 0%,var(--card) 44%);
  border:1px solid var(--line-cool);box-shadow:var(--shadow-sm);
  transition:transform .25s ease,box-shadow .25s ease,border-color .25s ease;
}
.pkg::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:5px;z-index:2;
  background:linear-gradient(180deg,var(--green) 0 22%,var(--navy-2) 22%,var(--navy) 100%);
}
.pkg.owned:hover{transform:translateY(-3px);box-shadow:0 20px 40px -22px rgba(16,36,68,.42);border-color:rgba(107,185,75,.6)}
.pkg.locked{background:linear-gradient(152deg,#f4f2ec 0%,#fbfaf7 44%);border-color:var(--line)}
.pkg.locked::before{background:linear-gradient(180deg,#c9d1de 0 22%,#aab4c5 22%,#9aa5b8 100%)}
.pkg.locked h3,.pkg.locked .pkg-price b{color:#5b6a80}
.pkg.locked:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:rgba(16,36,68,.22)}

.pkg-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.pkg-kicker{font-size:.66rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--green-deep);margin-bottom:7px}
.pkg.locked .pkg-kicker{color:var(--muted)}
.pkg h3{font-family:var(--serif);font-weight:600;font-size:1.38rem;color:var(--navy);line-height:1.1}
.pkg-badge{
  display:inline-flex;align-items:center;gap:6px;flex:none;
  font-size:.62rem;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  padding:6px 12px;border-radius:999px;
}
.pkg-badge.on{background:rgba(107,185,75,.16);color:var(--green-deep)}
.pkg-badge.off{background:rgba(16,36,68,.07);color:var(--muted)}
.pkg-badge svg{width:13px;height:13px}
.pkg p.blurb{color:var(--muted);font-size:.94rem;line-height:1.55;margin-top:12px;flex:1}

.pkg-meter{margin-top:18px;padding-top:16px;border-top:1px solid rgba(16,36,68,.13)}
.pkg-meter .row{display:flex;justify-content:space-between;font-size:.82rem;color:var(--muted);margin-bottom:8px}
.pkg-meter .row b{color:var(--green-deep);font-weight:800}
.bar{height:7px;border-radius:999px;background:var(--paper-2);overflow:hidden}
.bar span{display:block;height:100%;border-radius:999px;background:linear-gradient(90deg,var(--green),var(--green-d))}

.pkg-price{display:flex;align-items:baseline;gap:10px;margin-top:18px;padding-top:16px;border-top:1px solid rgba(16,36,68,.13)}
.pkg-price b{font-family:var(--serif);font-weight:600;font-size:1.6rem;color:var(--navy);line-height:1}
.pkg-price small{font-size:.68rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.pkg-price .count{margin-left:auto;font-size:.8rem;color:var(--muted);font-weight:600}
.pkg-alt{font-size:.82rem;color:var(--muted);margin-top:8px}
.pkg .btn{margin-top:18px}

/* checkout billing toggle */
.co-cycle{display:grid;grid-template-columns:1fr 1fr;gap:8px;background:var(--paper-2);
  border-radius:999px;padding:5px;margin-bottom:16px}
.co-cycle button{border:0;background:transparent;border-radius:999px;padding:11px 8px;cursor:pointer;
  font-size:.88rem;font-weight:700;color:var(--muted);transition:background .18s ease,color .18s ease;
  display:flex;flex-direction:column;align-items:center;gap:2px;line-height:1.2}
.co-cycle button span{font-size:.7rem;font-weight:600;opacity:.85}
.co-cycle button:hover{color:var(--navy)}
.co-cycle button[aria-pressed="true"]{background:var(--navy);color:#fff}
.co-cycle button[aria-pressed="true"] span{color:var(--green)}

/* ---------- training path ---------- */
.sec-head{margin:40px 0 20px}
.sec-head h2{font-family:var(--serif);font-weight:600;font-size:clamp(1.5rem,3vw,2rem);
  line-height:1.12;letter-spacing:-.01em;color:var(--navy);margin-top:12px}
.sec-head p{color:var(--muted);margin-top:8px;max-width:58ch}

.path-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px}
@media(max-width:980px){.path-grid{grid-template-columns:1fr}}

.pcard{
  position:relative;display:flex;flex-direction:column;
  background:var(--card);border:1px solid var(--line-cool);border-radius:20px;
  padding:26px 24px 24px;box-shadow:var(--shadow-sm);
  transition:transform .25s ease,box-shadow .25s ease,border-color .25s ease;
}
.pcard:hover{transform:translateY(-3px);box-shadow:0 20px 40px -22px rgba(16,36,68,.42)}
.pcard .pnum{
  position:absolute;top:-14px;left:24px;width:38px;height:38px;border-radius:50%;
  display:grid;place-items:center;font-family:var(--serif);font-weight:700;font-size:1.15rem;
  background:var(--navy);color:#fff;border:3px solid var(--paper);
}
.pcard.owned .pnum{background:var(--green);color:#0c2208}
.pcard.done .pnum{background:var(--green-deep);color:#fff}

.pcard .pvis{
  margin:-26px -24px 18px;border-radius:19px 19px 0 0;overflow:hidden;
  display:grid;place-items:center;min-height:96px;
  background:linear-gradient(150deg,#eef3fb,#f8fafd);
}
/* Full bleed: the artwork spans the whole card width rather than floating in
   a padded box, which is the only way it gets any real size at 367px. */
.pcard .pvis img{display:block;width:100%;height:auto}
/* Locked stages and stages with no artwork keep the old centred treatment. */
.pcard .pvis.empty{
  height:96px;border-radius:14px;margin:0 0 16px;
  border:1px solid var(--line-cool);
}
.pcard .plock{color:#9aa5b8}
.pcard .pvis .stage-word{font-family:var(--serif);font-weight:600;font-size:1.5rem;color:#b9c4d4}

.pbadge{
  display:inline-block;font-size:.63rem;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  padding:6px 12px;border-radius:999px;margin-bottom:10px;
}
.pbadge.now{background:rgba(107,185,75,.16);color:var(--green-deep)}
.pbadge.next{background:var(--green);color:#0c2208}
.pbadge.locked{background:rgba(16,36,68,.07);color:var(--muted)}
.pbadge.done{background:var(--green-deep);color:#fff}

.pcard h3{font-family:var(--serif);font-weight:600;font-size:1.45rem;color:var(--navy);line-height:1.1}
.pcard .psub{font-size:.8rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--green-deep);margin-top:5px}
.pcard.locked .psub{color:var(--muted)}
.pcard .pdesc{color:var(--muted);font-size:.93rem;line-height:1.55;margin-top:12px;flex:1}
.pcard .pfoot{margin-top:18px}
.pcard .pprice{display:flex;align-items:baseline;gap:8px;margin-top:14px}
.pcard .pprice b{font-family:var(--serif);font-weight:600;font-size:1.4rem;color:var(--navy);line-height:1}
.pcard .pprice small{font-size:.7rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.pcard.locked{background:linear-gradient(150deg,#f6f4ef,#fbfaf7)}
.pcard.locked .pvis{background:var(--paper-2);border-color:var(--line)}
.pcard.highlight{border-color:rgba(107,185,75,.65);box-shadow:0 18px 40px -20px rgba(86,161,56,.45)}

.path-note{margin-top:20px;color:var(--muted);font-size:.92rem;line-height:1.6;max-width:70ch}
.path-note a{color:var(--green-deep);font-weight:600}

/* ---------- extras row ---------- */
.extra-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
@media(max-width:980px){.extra-grid{grid-template-columns:1fr}}
.xcard{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:22px;
  display:flex;flex-direction:column;box-shadow:var(--shadow-sm);overflow:hidden}
.xcard .xvis{margin:-22px -22px 16px;border-radius:15px 15px 0 0;overflow:hidden}
.xcard .xvis img{display:block;width:100%;height:auto}
.xcard.owned{border-color:rgba(107,185,75,.5)}
.xcard h3{font-family:var(--serif);font-weight:600;font-size:1.2rem;color:var(--navy)}
.xcard .k{font-size:.63rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  color:var(--green-deep);margin-bottom:6px}
.xcard p{color:var(--muted);font-size:.9rem;line-height:1.5;margin-top:10px;flex:1}
.xcard .xprice{display:flex;align-items:baseline;gap:8px;margin-top:14px}
.xcard .xprice b{font-family:var(--serif);font-weight:600;font-size:1.3rem;color:var(--navy)}
.xcard .xprice small{font-size:.7rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.xcard .xalt{font-size:.8rem;color:var(--muted);margin-top:6px}
.xcard .btn{margin-top:16px}

.hub-note{padding:8px 0 60px;color:var(--muted);font-size:.88rem;max-width:62ch}
.hub-note a{color:var(--green-deep);font-weight:600}

/* ---------- player ---------- */
/* Fixed height with the overflow hidden, so getting this wrong does not make
   the page scroll, it makes the bottom of it unreachable. */
.player-body{height:var(--app-vh, 100dvh);overflow:hidden}
.player-shell{height:100%;display:flex;flex-direction:column}
/* The player has its own bar rather than the shared nav, so it needs the notch
   handled separately. Missing this is why the hub looked right in the app and
   a lesson did not: two headers, one fix. Height stays 70px and the inset is
   added as padding, so the bar grows to clear the status bar instead of the
   content sliding up into it. */
.player-nav{
  flex:none;height:70px;display:flex;align-items:center;gap:16px;
  padding:0 max(22px, env(safe-area-inset-right, 0px)) 0 max(22px, env(safe-area-inset-left, 0px));
  box-sizing:content-box;
  padding-top:env(safe-area-inset-top, 0px);
  background:rgba(246,243,236,.96);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-bottom:1px solid rgba(16,36,68,.12);
}
.player-nav .logo img{height:42px;width:auto}
.pn-back{display:inline-flex;align-items:center;gap:7px;color:var(--navy);font-size:.9rem;font-weight:600}
.pn-back:hover{color:var(--green-deep)}
.pn-divider{width:1px;height:26px;background:var(--line);flex:none}
.pn-course{min-width:0;flex:1}
.pn-course .k{font-size:.62rem;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--green-deep)}
.pn-course .n{font-family:var(--serif);font-weight:600;font-size:1.12rem;color:var(--navy);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-right{margin-left:auto;display:flex;align-items:center;gap:14px}
.pn-meter{display:flex;align-items:center;gap:10px}
.pn-meter .bar{width:118px}
.pn-meter span.count{font-size:.8rem;color:var(--muted);font-weight:700;font-variant-numeric:tabular-nums}
.pn-select{
  background:#fff;border:1.5px solid var(--line);border-radius:999px;
  padding:9px 14px;font-size:.86rem;font-weight:600;color:var(--navy);cursor:pointer;max-width:11rem;
}
.pn-select:focus{outline:none;border-color:var(--green)}
/* Labelled, not a bare hamburger. Three lines in the corner of a video player
   reads as "site menu" to most people, and the one thing a student actually
   wants from it is the list of lessons. The word does the work the icon
   cannot. */
.pn-burger{
  display:none;align-items:center;gap:7px;background:none;border:1.5px solid var(--line);
  cursor:pointer;padding:7px 12px 7px 9px;color:var(--navy);border-radius:999px;
  font-family:inherit;font-size:.85rem;font-weight:700;line-height:1;flex:none;
}
.pn-burger:hover{border-color:var(--navy)}
.pn-burger svg{flex:none}
.pn-burger-label{white-space:nowrap}

.player-body-row{flex:1;min-height:0;display:flex}
.scrim{display:none;position:fixed;inset:0;z-index:40;background:rgba(10,24,47,.45)}
.scrim.on{display:block}

.rail{
  width:320px;flex:none;background:var(--card);border-right:1px solid var(--line);
  display:flex;flex-direction:column;
}
.rail-head{flex:none;padding:16px 22px;border-bottom:1px solid var(--line-soft);display:flex;align-items:center;justify-content:space-between}
.rail-head .k{font-size:.66rem;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--green-deep)}
.rail-close{display:none;background:none;border:0;cursor:pointer;color:var(--muted);padding:4px}
.rail-list{flex:1;overflow-y:auto;padding-bottom:24px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.rail-list::-webkit-scrollbar{width:9px}
.rail-list::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.mod{
  padding:20px 22px 8px;font-size:.66rem;font-weight:800;letter-spacing:.15em;
  text-transform:uppercase;color:var(--muted);
}
.les{
  width:100%;display:flex;align-items:flex-start;gap:12px;text-align:left;
  padding:12px 22px;background:none;border:0;border-left:3px solid transparent;cursor:pointer;
  transition:background .16s ease,border-color .16s ease;
}
.les:hover{background:rgba(107,185,75,.07)}
.les.on{background:rgba(107,185,75,.11);border-left-color:var(--green)}
.les .dot{
  flex:none;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;margin-top:1px;
  border:1.5px solid var(--line-cool);background:#fff;
}
.les .dot svg{width:13px;height:13px}
.les.done .dot{background:var(--green);border-color:var(--green);color:#0c2208}
.les.open .dot{border-color:var(--navy);color:var(--navy)}
.les.shut .dot{background:var(--paper-2);border-color:var(--line);color:#97a2b3}
.les .t{min-width:0}
.les .t b{display:block;font-size:.92rem;font-weight:600;color:var(--ink);line-height:1.35}
.les.done .t b{color:var(--muted)}
.les.shut .t b{color:#8b95a6}
.les .t span{display:block;font-size:.76rem;color:var(--muted);margin-top:2px}
.rail-empty{padding:40px 22px;color:var(--muted);font-size:.92rem}

.stage{flex:1;min-width:0;overflow-y:auto;background:var(--paper)}
.stage-in{max-width:900px;margin:0 auto;padding:26px 26px 56px}

.screen{position:relative;border-radius:18px;overflow:hidden;background:var(--navy-ink);box-shadow:var(--shadow)}
.screen .frame{aspect-ratio:16/9;width:100%}
.screen iframe{width:100%;height:100%;border:0;display:block}
.screen-msg{
  position:absolute;inset:0;display:none;place-items:center;text-align:center;padding:30px;
  background:var(--navy-ink);color:#dbe3ef;
}
.screen-msg.on{display:grid}
.screen-msg h3{font-family:var(--serif);font-weight:600;font-size:1.4rem;color:#fff;margin-bottom:6px}
.screen-msg p{font-size:.94rem;color:#9fb0c9}

.lockwall{
  position:absolute;inset:0;z-index:20;display:none;place-items:center;text-align:center;padding:28px;
  background:
    radial-gradient(130% 110% at 50% 0%, rgba(107,185,75,.22), transparent 58%),
    linear-gradient(160deg,rgba(27,53,99,.97),rgba(10,24,47,.98));
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}
.lockwall.on{display:grid}
.lockwall .in{max-width:440px}
.lockwall .ico{
  width:58px;height:58px;border-radius:50%;display:grid;place-items:center;margin:0 auto 16px;
  background:rgba(107,185,75,.16);border:1.5px solid rgba(107,185,75,.5);color:var(--green);
}
.lockwall .tag{
  display:inline-flex;align-items:center;background:var(--green);color:#0c2208;
  font-size:.64rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  padding:6px 13px;border-radius:999px;margin-bottom:12px;
}
.lockwall h2{font-family:var(--serif);font-weight:600;font-size:clamp(1.5rem,3.4vw,2rem);color:#fff;line-height:1.12}
.lockwall p{color:#bccbe0;font-size:.96rem;margin-top:12px;line-height:1.6}
.lockwall .acts{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:24px}

/* ---------- trainer variant selector ---------- */
.demos{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  margin-top:14px;padding:14px 18px;border-radius:14px;
  background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-sm);
}
.demos .k{font-size:.66rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
.demos select{
  background:#fff;border:1.5px solid var(--line);border-radius:999px;
  padding:10px 16px;font-size:.9rem;font-weight:600;color:var(--navy);cursor:pointer;min-width:13rem;
}
.demos select:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 4px rgba(107,185,75,.16)}
.demos .dognote{font-size:.86rem;color:var(--muted);margin-left:auto}
@media(max-width:620px){
  .demos{gap:10px}
  .demos select{min-width:100%}
  .demos .dognote{margin-left:0;width:100%}
}

/* ---------- recommended path (soft gating) ---------- */
.les.ahead .t b{color:#93a0b2}
.les.ahead .dot{opacity:.55}
.upnext{
  display:inline-block;margin-top:4px;font-size:.62rem;font-weight:800;letter-spacing:.12em;
  text-transform:uppercase;color:#0c2208;background:var(--green);padding:3px 9px;border-radius:999px;
}
.ahead-note{
  display:none;align-items:center;gap:14px;flex-wrap:wrap;
  margin-top:14px;padding:14px 18px;border-radius:14px;
  background:#fdf8ec;border:1px solid #ecdcb4;color:#6b5417;font-size:.92rem;line-height:1.5;
}
.ahead-note.on{display:flex}
.ahead-note b{color:#4a3a0f;font-weight:700}
.ahead-note .btn{margin-left:auto;padding:10px 18px;font-size:.85rem}
@media(max-width:620px){.ahead-note .btn{margin-left:0;width:100%}}

.meta{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;flex-wrap:wrap;margin-top:26px}
.meta .k{font-size:.66rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--green-deep);margin-bottom:8px}
.meta h1{font-family:var(--serif);font-weight:600;font-size:clamp(1.6rem,3.2vw,2.15rem);line-height:1.1;letter-spacing:-.01em;color:var(--navy)}
.pill{
  display:inline-flex;align-items:center;gap:7px;flex:none;
  font-size:.68rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  padding:8px 14px;border-radius:999px;background:var(--paper-2);color:var(--muted);
}
.pill svg{width:13px;height:13px}
.pill.done{background:rgba(107,185,75,.16);color:var(--green-deep)}
.pill.open{background:rgba(16,36,68,.08);color:var(--navy)}

.notes{margin-top:30px;background:var(--card);border:1px solid var(--line);border-radius:18px;padding:22px;box-shadow:var(--shadow-sm)}
/* Student examples: the link under the trainer dropdown, and the pop up. */
.ex-open{
  display:inline-flex;align-items:center;gap:8px;margin-top:12px;
  background:none;border:0;padding:0;cursor:pointer;
  font:inherit;font-size:.88rem;font-weight:700;color:var(--green-deep);
  text-decoration:underline;text-underline-offset:3px;
}
.ex-open:hover{color:var(--navy)}

/* The student example strip that sits under the video. One tile per owner, so
   the number of different dogs and handlers who filmed this exercise is
   visible without opening anything. Vimeo thumbnails are painted on when they
   arrive; the lettered face underneath is the finished state when they do not,
   which is why there is no spinner and no empty grey box here. */
.exrow{margin-top:16px}
.exrow-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}
.exrow-k{
  display:inline-flex;align-items:center;gap:7px;
  font-size:.63rem;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;color:var(--green-deep);
}
.exrow-count{
  flex:none;font-size:.68rem;font-weight:800;letter-spacing:.04em;color:var(--muted);
  background:var(--paper-2);border-radius:999px;padding:4px 10px;
}
/* flex-start, not the default stretch. A button centres its own contents, so a
   tile with no caption was being stretched to match its named neighbours and
   then centring its thumbnail inside that extra height, which dropped it half
   a line below the rest of the row. */
.exrow-track{
  display:flex;align-items:flex-start;gap:10px;overflow-x:auto;min-width:0;max-width:100%;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;padding-bottom:4px;
}
.exrow-track::-webkit-scrollbar{display:none}
/* Sized as a fraction of the row rather than a fixed width, so a slice of the
   next tile is always cut off at the right edge. That overhang is the only
   thing telling a student on a phone that there are six of these and not
   three. Clamped at the top so the tiles do not become billboards on a wide
   screen. */
.extile{
  flex:0 0 clamp(112px,28%,150px);scroll-snap-align:start;
  display:block;text-align:left;padding:0;border:0;background:none;
  font:inherit;cursor:pointer;
}
.extile-shot{
  position:relative;display:block;width:100%;aspect-ratio:16/9;
  border-radius:11px;overflow:hidden;
  background:linear-gradient(150deg,var(--navy-2),var(--navy-ink));
  background-size:cover;background-position:center;
  box-shadow:var(--shadow-sm);transition:transform .16s ease,box-shadow .16s ease;
}
.extile:hover .extile-shot{transform:translateY(-2px);box-shadow:0 10px 20px -10px rgba(10,24,47,.45)}
.extile-letter{
  position:absolute;inset:0;display:grid;place-items:center;
  font-size:1.5rem;font-weight:800;color:rgba(255,255,255,.34);
}
/* Once a real frame is behind it the letter would fight the picture. */
.extile-shot.has-shot .extile-letter{display:none}
.extile-play{
  position:absolute;right:7px;bottom:7px;width:22px;height:22px;border-radius:50%;
  display:grid;place-items:center;background:rgba(255,255,255,.92);color:var(--navy);
  box-shadow:0 2px 6px rgba(10,24,47,.3);
}
.extile-play svg{width:12px;height:12px;margin-left:1px}
.extile-name{
  display:block;margin-top:8px;font-size:.79rem;font-weight:700;color:var(--navy);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.extile-note{
  display:block;margin-top:1px;font-size:.72rem;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
@media(max-width:600px){
  .exrow{margin-top:14px}
  .extile-name{font-size:.76rem}
}
.ex-scrim{position:fixed;inset:0;background:rgba(10,24,47,.55);z-index:70}
.ex-modal{
  position:fixed;z-index:71;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(760px,calc(100vw - 32px));
  /* var(--app-vh), not 100vh. Inside the app 100vh reports the height of the
     device screen rather than the height the page actually has, so this was
     sizing the modal to roughly 884px inside a viewport a third of that and
     pushing the video below the fold. The landscape rules further down were
     fixed earlier; this is the portrait case, which had the same fault. */
  max-height:calc(var(--app-vh, 100dvh) - 48px);
  display:flex;flex-direction:column;overflow:hidden;
  background:var(--card);border-radius:20px;box-shadow:0 24px 60px rgba(10,24,47,.32);
}
.ex-head{
  display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  padding:20px 22px 14px;border-bottom:1px solid var(--line);
}
.ex-head .k{font-size:.63rem;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--green-deep)}
.ex-head .e{font-family:var(--serif);font-size:1.15rem;color:var(--navy);margin-top:4px}
.ex-body{padding:18px 22px 22px;overflow-y:auto}
.ex-carousel{position:relative;min-width:0}
/* Scroll snapping rather than drag handling, so the swipe is the browser's
   own and behaves the way every other carousel on the phone does. */
/* min-width:0 for the same reason as the dog tabs on the profile page: a flex
   container's default minimum is its content, so without this it widens to fit
   the slides instead of scrolling them, and the overflow escapes to the page. */
.ex-track{
  display:flex;overflow-x:auto;min-width:0;max-width:100%;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
}
.ex-track::-webkit-scrollbar{display:none}
.ex-slide{flex:0 0 100%;min-width:100%;scroll-snap-align:start;scroll-snap-stop:always}
/* aspect-ratio rather than the old padding-top trick. The trick derives height
   from width and nothing else, which is fine in portrait and wrong in
   landscape: a 16:9 box as wide as a phone on its side is taller than the phone
   is, so the video runs off the bottom of the modal and has to be scrolled to.
   An explicit ratio lets the landscape rules below drive the box from its
   height instead, and the width follows. */
.ex-frame{
  position:relative;aspect-ratio:16/9;width:100%;margin:0 auto;
  background:#000;border-radius:12px;overflow:hidden;
}
.ex-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.ex-missing{position:absolute;inset:0;display:grid;place-items:center;color:#fff;font-size:.9rem}
.ex-caption{margin-top:12px;font-size:.9rem;color:var(--muted);text-align:center}
.ex-nav{
  position:absolute;top:calc(28.125% - 20px);width:40px;height:40px;border-radius:50%;
  border:1px solid var(--line);background:rgba(255,255,255,.94);color:var(--navy);
  display:grid;place-items:center;cursor:pointer;padding:0;
  box-shadow:0 4px 14px rgba(10,24,47,.18);
}
.ex-nav.prev{left:10px}
.ex-nav.next{right:10px}
.ex-nav:disabled{opacity:0;pointer-events:none}
.ex-dots{display:flex;justify-content:center;gap:8px;margin-top:16px}
.ex-dot{
  width:9px;height:9px;border-radius:50%;border:0;padding:0;
  background:var(--line);cursor:pointer;transition:width .18s ease,background .18s ease;
}
.ex-dot.on{background:var(--navy);width:24px;border-radius:5px}
@media(max-width:600px){
  .ex-modal{width:calc(100vw - 20px);border-radius:16px}
  .ex-body{padding:14px 16px 18px}
  .ex-head{padding:16px 16px 12px}
}

select.field-select{
  -webkit-appearance:none;appearance:none;background-color:#fff;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23102444' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;padding-right:42px;
}
label.def{display:flex;align-items:center;gap:7px;cursor:pointer}
label.def input[type=checkbox],label.def input[type=radio]{accent-color:var(--green);width:16px;height:16px}

/* A lesson the student owns that has not opened yet. Distinct from .shut,
   which means they have not bought it: one is a wait, the other is a sale, and
   showing the same treatment for both is how you get "why am I being asked to
   pay again". */
.les.waiting{opacity:.72;cursor:pointer}
.les.waiting .dot{background:rgba(16,36,68,.06);color:var(--muted);border-color:var(--line)}
.les.waiting b{color:var(--muted)}
.les .soon{
  display:inline-block;margin-top:4px;font-size:.66rem;font-weight:800;
  letter-spacing:.08em;text-transform:uppercase;color:var(--green-deep);
  background:rgba(107,185,75,.14);border-radius:999px;padding:2px 9px;
}
.lockwall.waiting .ico{background:rgba(107,185,75,.14);color:var(--green-deep)}
.lockwall.waiting .tag{color:var(--green-deep)}
.lockwall #lock-buy[hidden]{display:none}

.wk9-badge{
  display:inline-block;margin-left:7px;min-width:18px;padding:1px 6px;
  background:#c0492c;color:#fff;border-radius:999px;
  font-size:.68rem;font-weight:800;line-height:1.5;text-align:center;vertical-align:middle;
}
.wk9-badge[hidden]{display:none}

.bk-row{
  display:flex;gap:11px;align-items:flex-start;padding:11px 0;
  border-bottom:1px solid var(--line-soft);cursor:pointer;
}
.bk-row:last-child{border-bottom:0}
.bk-row input{margin-top:3px;accent-color:var(--green);width:16px;height:16px;flex:none}
.bk-row b{display:block;color:var(--navy);font-size:.88rem;word-break:break-all}
.bk-row .bk-note{display:block;font-size:.78rem;color:var(--muted);margin-top:2px}

/* Admin drawers. These were written inline in curriculum.html, which meant any
   other staff page using the same markup got a plain block at the bottom of
   the page instead of an overlay. Shared here so that cannot happen again. */
.adm-scrim{position:fixed;inset:0;background:rgba(10,24,47,.45);z-index:11500}
/* A full height panel pinned to every edge, so in the app it runs under both
   the status bar at the top and the home indicator at the bottom. Now that
   admin ships inside the app rather than being web only, it needs the same
   insets as everything else. */
.adm-drawer{
  position:fixed;top:0;right:0;bottom:0;width:min(94vw,460px);z-index:11600;
  background:var(--paper);border-left:1px solid var(--line);box-shadow:var(--shadow-lg);
  display:flex;flex-direction:column;
  padding-top:env(safe-area-inset-top, 0px);
  padding-bottom:env(safe-area-inset-bottom, 0px);
}
.adm-drawer[hidden]{display:none}
.adm-drawer-head{
  flex:none;padding:20px 24px;border-bottom:1px solid var(--line);
  display:flex;align-items:flex-start;justify-content:space-between;gap:14px;
}
.adm-drawer-head .k{font-family:var(--serif);font-weight:600;font-size:1.25rem;color:var(--navy);line-height:1.2}
.adm-drawer-head .e{font-size:.84rem;color:var(--muted);margin-top:3px}
.adm-drawer-body{flex:1;overflow-y:auto;padding:20px 24px}
.adm-drawer-foot{flex:none;padding:16px 24px;border-top:1px solid var(--line);display:flex;gap:10px;background:var(--card)}
.adm-drawer-foot .btn{flex:1}
.adm-muted{font-size:.88rem;color:var(--muted);line-height:1.55}

/* How lessons arrive. Navy rather than green, because it is information
   rather than an invitation to do something. */
.paced{
  display:flex;align-items:center;gap:18px;margin-top:24px;
  background:var(--card);border:1px solid var(--line-cool);
  border-left:4px solid var(--navy);border-radius:16px;padding:18px 20px;
  box-shadow:var(--shadow-sm);
}
.paced[hidden]{display:none}
.paced .dp-icon{
  flex:none;width:46px;height:46px;border-radius:50%;display:grid;place-items:center;
  background:rgba(16,36,68,.07);color:var(--navy);
}
.paced .dp-copy{flex:1;min-width:0}
.paced .dp-copy b{display:block;font-family:var(--serif);font-size:1.05rem;color:var(--navy)}
.paced .dp-copy span{display:block;font-size:.86rem;color:var(--muted);line-height:1.55;margin-top:4px}
@media(max-width:700px){ .paced{gap:14px;padding:16px} }

/* The hub nudge to fill in the dog profile. */
.dogprompt{
  display:flex;align-items:center;gap:18px;margin-top:24px;
  background:var(--card);border:1px solid rgba(107,185,75,.45);
  border-left:4px solid var(--green);border-radius:16px;padding:18px 20px;
  box-shadow:var(--shadow-sm);
}
.dogprompt[hidden]{display:none}
.dogprompt .dp-icon{
  flex:none;width:46px;height:46px;border-radius:50%;display:grid;place-items:center;
  background:rgba(107,185,75,.14);color:var(--green-deep);
}
.dogprompt .dp-copy{flex:1;min-width:0}
.dogprompt .dp-copy b{display:block;font-family:var(--serif);font-size:1.05rem;color:var(--navy)}
.dogprompt .dp-copy span{display:block;font-size:.86rem;color:var(--muted);line-height:1.55;margin-top:4px}
.dogprompt .dp-acts{flex:none;display:flex;align-items:center;gap:14px}
@media(max-width:700px){
  .dogprompt{flex-wrap:wrap;gap:14px}
  .dogprompt .dp-acts{width:100%;justify-content:space-between}
}

/* Questions on a lesson, and the ask box. */
.qa{margin-top:30px;background:var(--card);border:1px solid var(--line);
  border-radius:18px;padding:22px;box-shadow:var(--shadow-sm)}
.qa-item{border-bottom:1px solid var(--line-soft);padding:14px 0}
.qa-item:last-child{border-bottom:0;padding-bottom:0}
.qa-item summary{
  cursor:pointer;font-weight:700;color:var(--navy);font-size:.95rem;line-height:1.5;
  list-style:none;display:flex;gap:10px;align-items:flex-start;
}
.qa-item summary::-webkit-details-marker{display:none}
.qa-item summary::before{
  content:"";flex:none;width:8px;height:8px;margin-top:7px;border-right:2px solid var(--green);
  border-bottom:2px solid var(--green);transform:rotate(-45deg);transition:transform .18s ease;
}
.qa-item[open] summary::before{transform:rotate(45deg)}
.qa-answer{
  margin-top:10px;padding-left:18px;white-space:pre-wrap;line-height:1.65;
  font-size:.92rem;color:var(--muted);
}
.qa-hint{font-size:.8rem;color:var(--muted);line-height:1.5;margin-top:8px}

.homework{
  margin-top:30px;background:rgba(107,185,75,.07);
  border:1px solid rgba(107,185,75,.42);border-left:4px solid var(--green);
  border-radius:18px;padding:22px;
}
.homework .k{color:var(--green-deep)}
.homework .hw-body{
  white-space:pre-wrap;font-size:1rem;line-height:1.65;color:var(--navy);
}
.notes-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}
.notes-head .k{font-size:.66rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
.notes-head .status{font-size:.78rem;color:var(--muted)}
.acts-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px}
.acts-row .btn-green{flex:1;min-width:17rem;padding:16px 26px;font-size:1rem}

.toast{
  position:fixed;left:50%;transform:translateX(-50%);z-index:11000;
  bottom:calc(26px + env(safe-area-inset-bottom, 0px));
  background:var(--navy);color:#fff;font-size:.92rem;font-weight:600;
  padding:14px 22px;border-radius:999px;box-shadow:var(--shadow-lg);display:none;max-width:90vw;text-align:center;
}
.toast.on{display:block}

@media(max-width:900px){
  .player-nav{
    height:62px;gap:10px;
    padding:0 max(12px, env(safe-area-inset-right, 0px)) 0 max(12px, env(safe-area-inset-left, 0px));
    padding-top:env(safe-area-inset-top, 0px);
  }
  .player-nav .logo,.pn-divider,.pn-meter{display:none}

  /* My Hub stays on phones. Leaving the way out at the bottom of the page only
     means a student who wants to go back has to scroll past the whole lesson
     to find it. The label drops on the narrowest screens; the chevron alone is
     understood. */
  /* Outermost control on the left, ahead of Lessons. Back sits at the edge on
     every phone screen ever made, and putting it anywhere else makes people
     hunt. Label drops on narrow screens; the chevron carries it. */
  .pn-back{flex:none;gap:4px;font-size:.85rem;order:-1}
  .pn-burger{display:inline-flex;margin-left:-2px}
  .pn-course .k{font-size:.58rem;letter-spacing:.12em}
  .pn-course .n{font-size:1rem}
  /* Takes the space between the left controls and Sign out, so the picker
     inside it can centre against the bar rather than hug the right edge. */
  .pn-right{flex:1;gap:8px;min-width:0;justify-content:flex-end}
  /* Centred and given room to show a whole course name. "Introductory Course"
     truncated to "Introductor" is worse than no label at all, so this is the
     control that gets the leftover width rather than the one that gives it up.
     text-align-last centres the closed state; text-align alone does not. */
  .pn-select{
    max-width:none;flex:0 1 12rem;min-width:0;margin:0 auto;
    padding:8px 26px 8px 12px;font-size:.85rem;
    text-align:center;text-align-last:center;
  }
  .wk9-out{padding:8px 14px;font-size:.82rem}
  .rail{
    /* Pinned directly beneath the player bar. The bar is now taller by the
       inset, so a flat 62px would slide the lesson list up underneath it. */
    position:fixed;top:calc(62px + env(safe-area-inset-top, 0px));
    bottom:0;left:0;z-index:50;width:min(78vw,300px);
    transform:translateX(-102%);transition:transform .22s ease;box-shadow:var(--shadow-lg);
  }
  .rail.on{transform:none}
  .rail-close{display:block}
  .stage-in{padding:18px 16px 46px}
  .acts-row .btn-green{min-width:100%}
}

/* On a phone the course name and the course picker say the same thing, so the
   name gives way and the picker carries it. */
@media(max-width:560px){
  .player-nav .pn-course{display:none}
  .player-nav{gap:6px}
  .pn-right{flex:1;margin-left:0;justify-content:flex-end;min-width:0}

  /* font-size is set to 16px by the iOS zoom rule near the end of this file;
     setting it here as well would only be a second answer to the same
     question. */
  .pn-select{flex:0 1 10.5rem;padding:8px 24px 8px 10px}
  .wk9-out{flex:none;padding:8px 12px;font-size:.8rem}

  /* Chevron only. "My Hub" beside it is the first thing to go when the row
     runs out of room, and an arrow pointing left is not ambiguous. */
  .pn-back{font-size:0;gap:0;padding:6px 2px}
  .pn-back svg{width:20px;height:20px}

  /* The burger keeps its word. It is the control students need most in a
     lesson and the one they are least likely to guess at. */
  .pn-burger{padding:7px 10px 7px 8px;font-size:.8rem;gap:5px}
  .pn-burger svg{width:20px;height:20px}
}
/* A phone held sideways. Short and wide, and the whole point of turning it is
   to make the video bigger, so the video is sized to the height that is
   actually there and everything around it gives way. dvh rather than vh
   because Safari's toolbars change the usable height as you scroll, and vh
   measures the taller state, which is how content ends up under the bottom
   edge. */
@media(max-height:560px) and (orientation:landscape){
  .ex-modal{
    max-height:calc(var(--app-vh, 100dvh) - 16px);
    width:min(100vw - 24px, 100vw);
  }
  .ex-head{padding:10px 18px 8px}
  .ex-head .e{font-size:1rem}
  .ex-body{padding:10px 18px 14px}

  /* Sized by what is actually left rather than by a guess.

     The first attempt subtracted a fixed number of pixels for the header, the
     padding and the dots. That number is a guess about chrome whose height
     depends on the text in it, and when the guess is low the video is taller
     than the space and the body scrolls, which is the thing being fixed.

     So the modal becomes a flex column of a known height, the body takes
     whatever the header leaves, the carousel takes whatever the dots leave,
     and the video is told to be exactly as tall as the carousel. Every step
     measures instead of assuming, and the video cannot overflow because
     nothing above it is free to grow. */
  .ex-modal{display:flex;flex-direction:column;height:calc(var(--app-vh, 100dvh) - 16px)}
  .ex-head{flex:none}
  .ex-body{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}
  .ex-carousel{flex:1;min-height:0}
  .ex-track{height:100%}
  .ex-slide{display:flex;align-items:center;justify-content:center}
  .ex-frame{height:100%;width:auto;max-width:100%;flex:none}
  .ex-dots{flex:none}

  /* The caption is the student's name and their dog. Worth reading, not worth
     the vertical space that would push the video off screen. */
  .ex-caption{display:none}

  /* The arrows were positioned against a box whose height came from its width.
     Now that the box is sized by height, centre them on it properly. */
  .ex-nav{top:calc(50% - 20px)}
  .ex-dots{margin-top:8px}

  /* The main lesson video has exactly the same problem as the examples: a 16:9
     box as wide as a sideways phone is taller than the phone. Capping the
     width of the whole screen block by the height available keeps the ratio
     intact and centres it, so turning the phone makes the video bigger rather
     than pushing its bottom half off the page.

     1.7778 is 16/9. Written as a number because calc cannot divide by a
     ratio. */
  .screen{max-width:calc((var(--app-vh, 100dvh) - 150px) * 1.7778);margin-left:auto;margin-right:auto}
}

/* ---------------------------------------------------------------------------
   iOS ZOOM ON FOCUS

   Tapping a text field whose font-size is under 16px makes iOS zoom the page
   in, so the text is readable while typing. It does not zoom back out
   afterwards. Everything that followed came from that one behaviour: the page
   ends up about 107% wide, so it can be panned side to side, and every fixed
   element is laid out against a viewport wider than the screen, which is how
   the close button on the assistant ended up past the right edge and why
   reaching for it dragged the header down instead.

   The fix is to give anything focusable at least 16px on a phone. Nothing
   about the zoom is configurable and disabling pinch zoom entirely would fix
   the symptom by taking away a thing people with poor eyesight rely on.

   Applied by width rather than by pointer type, because a narrow window on a
   desktop is not a phone and does not have this problem, but is also not
   harmed by a slightly larger control. */
@media(max-width:900px){
  /* .demos select is listed by name on purpose. A bare `select` here loses to
     `.demos select` on specificity no matter how far down the file it sits, so
     the general rule alone left the trainer picker at 14px and it went on
     zooming the page. Anything else that styles a control through a parent
     class needs adding here too. */
  input, textarea, select,
  .field, .pn-select, select.field-select,
  .demos select {
    font-size:16px;
  }

  /* Padding trimmed so the control keeps its shape at the larger text size. */
  .demos select{padding:8px 14px}

  /* Padding comes back down so the course picker stays the size it was. The
     text is bigger; the control is not. */
  .pn-select{padding:7px 22px 7px 10px}
}
@media(max-width:560px){
  .pn-select{padding:7px 20px 7px 9px;flex:0 1 11.5rem}
}

@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
