/* =========================================================================
   lpen-legacy-course.css — the legacy (2021) course description page.

   EVERY SELECTOR CONTAINS ONE OF THIS PAGE'S SECTION IDS, and
   build_legacy_course.py fails the build if one does not. lpen-assets/ is
   enqueued site wide (CLAUDE.md §18j), so a single unanchored rule here
   repaints something on every page of the site. An id anchor is a fact you
   can grep; prefix scoping is a transformation you have to trust (§18k).

   Colour, type and spacing are set on the widgets themselves wherever
   Elementor can express them, so the team can change them in the editor.
   What is here is only what Elementor cannot do: sticky positioning, a
   nested list, multi-column flow, an object-fit crop, and a shared border on
   a group of rows.

     1  tokens
     2  hero, on the photograph
     3  the session block                       §9.3
     4  the CPD credit block, EXPIRED state     §9.1
     5  the course outline
     6  instructor cards                        §9.7
     7  purchasing options: the sticky band      §9.8
     8  focus and motion
   ========================================================================= */

/* ------------------------------------------------------------ 1 tokens */
/* Declared on the two ids that own subtrees, then inherited. There is no
   :root block: an unanchored :root in a site wide stylesheet is exactly the
   leak the build guard exists to prevent. */
#lpen-l21-hero,
#lpen-l21-notice,
#lpen-l21-body {
  --l21-navy-900: #012032;
  --l21-navy-800: #022e48;
  --l21-navy-700: #0b4465;
  --l21-navy-100: #c9dde8;
  --l21-navy-50: #e5eef3;
  --l21-navy-25: #f3f7f9;
  --l21-action: #0f5c96;
  --l21-gold-500: #c8901f;
  --l21-gold-300: #e8b64a;
  --l21-ink: #111820;
  --l21-muted: #4a5666;
  --l21-subtle: #6b7684;
  --l21-border: #cfd6dd;
  --l21-border-strong: #78848f;
  --l21-surface-1: #f6f8fa;
  --l21-surface-2: #eef2f5;
  --l21-white: #fff;
  --l21-focus: #6a3fd4;
  --l21-elev-2: 0 4px 16px rgba(1, 32, 50, 0.12);
}

/* --------------------------------------------- 2 hero, on the photograph */
/* The photograph is 980x552 and sits under a navy overlay, so the white
   heading is measured against the overlay rather than against whatever pixel
   of the picture happens to be behind a given letter. Elementor sets the
   image and the overlay; this only guards the two things it cannot. */
#lpen-l21-hero {
  position: relative;
  overflow: hidden;
}

/* A long course title on a photograph at 390px is the worst case, and
   "The Complete Guide To Study Permits and Study Plans 2021" is long. */
#lpen-l21-hero .elementor-heading-title {
  text-wrap: balance;
}

/* ------------------------------------------------- 3 the session block */
/* §9.3: surface-1 with a border-strong LEFT rule. Elementor can paint a
   border on all four sides or none, so the single edge is here. */
#lpen-l21-session {
  border-left: 3px solid var(--l21-border-strong);
}

/* The three facts sit on one baseline in an Elementor GRID container, not a
   flex row, so a wrapped value never drags its neighbours' labels down. That
   is a native control, so there is no layout rule here at all. */
#lpen-l21-session time {
  font-weight: 700;
  color: var(--l21-ink);
}

/* -------------------------------- 4 the CPD credit block, EXPIRED state */
/* ⚠️ NOT GOLD, AND THAT IS THE POINT.
   §9.1 makes this a state machine and gold is the APPROVED state: it is the
   one signal on the site that says "this is a credit you can still earn".
   This course's own last line reads "Video recording valid until February 24,
   2022". Painting a lapsed approval gold would be a claim the block itself
   contradicts, two paragraphs apart, to an audience regulated on exactly that
   point. Owner's decision, 2026-08-26.

   So: surface-1 with a border-strong rule, which §9.1 already specifies for
   the state that is not a granted credit. Every word, hour figure and date
   inside is verbatim. */
#lpen-l21-cpd {
  border: 1px solid var(--l21-border-strong);
  border-top: 3px solid var(--l21-border-strong);
}

/* The rules between regulators are real `divider` widgets, not a CSS
   sibling selector: containers drop `_css_classes` (§18b.2), and a divider
   is editable in the Navigator where a generated border is not. */

/* ⚠️ Elementor centres an icon-list bullet against the whole item, so on a
   two-line entry the dot floats in the middle of nowhere. Three of the seven
   approval lines here wrap, including the longest one in the block. Top
   align, and nudge the dot onto the first line's optical centre. */
#lpen-l21-cpd .elementor-icon-list-item {
  align-items: flex-start;
}

#lpen-l21-cpd .elementor-icon-list-icon {
  margin-top: 5px;
}

/* The Law Society of Ontario accreditation badge. 100x58, and it is a badge,
   so it must neither stretch to the column nor centre itself under copy that
   is left aligned. */
#lpen-l21-cpd .lpen-l21-badge img {
  width: 100px;
  height: auto;
  max-width: 100px;
}

/* ---------------------------------------------- 5 the course outline */
/* 4928 holds all 40 lines in ONE paragraph, separated by <br> and indented
   with non-breaking spaces. That indentation is the only thing carrying the
   structure and it collapses the moment the line wraps, which on a phone is
   most of them. This is a real nested list.

   Two columns on desktop, because 40 items in one column is a scroll and
   nothing else. `break-inside: avoid` keeps a parent and its children
   together; without it a sub-list is orphaned at the top of column two under
   nothing. */
#lpen-l21-outline .lpen-l21-list {
  columns: 2;
  column-gap: 44px;
}

/* ⚠️ THE OUTLINE BREAKS OUT WIDER THAN THE ARTICLE, TO THE RIGHT ONLY.
   The page looked empty and the article looked narrow, but the prose is
   already the widest thing on it: measured in the browser, the biographies
   run 89 characters a line against the 65 to 75 the design system asks for
   (§5.4), so widening the COLUMN would have made reading worse, not better.

   What is actually too narrow is this block, which is 36 items in two 330px
   columns, and it is a list rather than prose, so the measure rule does not
   apply to it. Extending right lands its right edge exactly on the sticky
   band's right edge, while the left edge stays aligned with every other
   section. Three columns of about 300px.

   ⚠️ 200, not 180. 180 is the arithmetic difference between the 760 article
   and the 1120 band, but Elementor's own 10px of container padding sits on
   each side of the list, so the measured right edge landed 20px short of the
   band. Measured, then corrected.

   Right only, deliberately: breaking out on both sides would leave the list
   starting 200px left of its own heading. */
@media (min-width: 1180px) {
  #lpen-l21-outline .lpen-l21-list {
    columns: 3;
    column-gap: 40px;
    margin-right: -200px;
  }
}

@media (max-width: 900px) {
  #lpen-l21-outline .lpen-l21-list {
    columns: 1;
  }
}

#lpen-l21-outline ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

#lpen-l21-outline .lpen-l21-list > ul > li {
  break-inside: avoid;
  page-break-inside: avoid;
  margin: 0 0 10px;
}

#lpen-l21-outline li {
  position: relative;
  padding-left: 18px;
  color: var(--l21-ink);
  font-size: 17px;
  line-height: 27px;
}

/* The bullet is drawn, not typed. 4928 types a literal "•" into the copy,
   which a screen reader reads out as "bullet" on all 40 lines and which no
   list semantics can suppress. Real <li> plus ::before gives the same picture
   and a navigable list. */
#lpen-l21-outline li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 11px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--l21-action);
}

/* Level two and three step in, get lighter, and lose the filled bullet, so
   depth is legible without relying on indentation alone. */
#lpen-l21-outline li li {
  margin-top: 8px;
  color: var(--l21-muted);
  font-size: 16px;
  line-height: 25px;
}

#lpen-l21-outline li li::before {
  background: none;
  border: 1px solid var(--l21-border-strong);
}

#lpen-l21-outline li li li::before {
  border-radius: 0;
  height: 1px;
  width: 7px;
  top: 12px;
  border: 0;
  background: var(--l21-border-strong);
}

#lpen-l21-outline ul ul {
  margin: 6px 0 0;
  padding-left: 14px;
  border-left: 1px solid var(--l21-border);
}

/* ------------------------------------------------- 6 instructor cards */
/* §9.7. 4928 drops each headshot in at its natural size: 385x737 and
   369x900, centre aligned, so the two cards are wildly different heights and
   the page pogos. A fixed box with object-fit gives one shape.

   ⚠️ Both are portraits, so a centred square crop lands on the chin. The
   focal point per person is generated from FACULTY[].focus at the foot of
   this file. */
/* ⚠️ The WIDGET is the flex item, not a container around it.
   A container was the obvious way to hold the photo at 132px and it does not
   work: `_flex_shrink: 0` never reaches the page (§18l, same as
   `_flex_basis`), so the column shrank to 107px, Elementor's own 10px
   container padding came off that, and the img's `max-width: 100%` clamped it
   to 87px while `height: 132px` held. A portrait squeezed to 87x132, on a
   page whose whole point was that the two headshots finally match. Measured,
   not guessed.

   `aspect-ratio` rather than a fixed height, so the square follows the width
   in both flex directions and the mobile size is one number. */
#lpen-l21-fac .lpen-l21-face {
  flex: 0 0 auto;
  width: 132px;
  align-self: flex-start;
}

#lpen-l21-fac .lpen-l21-face img {
  width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
  object-fit: cover;
  border-radius: 8px;
  display: block;
}

@media (max-width: 767px) {
  #lpen-l21-fac .lpen-l21-face {
    width: 96px;
  }
}

/* The photograph sits BESIDE the credentials, not above them: §9.7 says
   credentials matter to this audience more than photographs do, and a 132px
   picture stacked on top pushes the licence line below the fold of the card.
   That row is an Elementor flex container with an explicit mobile stack, so
   there is no rule for it here.

   Social links. 4928 renders these as Font Awesome brand glyphs in circles
   (§18a: four live fa- classes on this page). These are Tabler icon-list
   items, so they need to read as a row of links rather than a bullet list. */
#lpen-l21-fac .lpen-l21-social .elementor-icon-list-item a {
  text-decoration: none;
}

#lpen-l21-fac .lpen-l21-social .elementor-icon-list-item a:hover {
  text-decoration: underline;
}

/* ---------------------- 7 purchasing options: the sticky notice band */
/* This component has been through three shapes in one day, and the reasons
   are worth keeping because each one was right about the previous one.

   1. A sticky SIDE RAIL. It held one small card and then about 400px of empty
      white for four fifths of a long page, and squeezed the article into 64%
      of the width to do it.
   2. A static band plus a sticky BOTTOM BAR. `position: sticky; bottom: 0`
      docks at the end of its containing block, which is the point of it, and
      that meant the bar released above the site footer and vanished exactly
      when a reader who had got that far might want it. Owner, 2026-08-26:
      "the bottom bar gets lost when it gets to the bottom." It did.
   3. This: one slim band, at the top, stuck.

   A TOP-stuck element cannot go missing the way a bottom-stuck one does. Its
   sticky range runs from its own position to the bottom of its containing
   block, and its containing block is the Elementor page wrapper, so it stays
   pinned for the entire article and only leaves as the footer arrives. */
#lpen-l21-notice {
  position: sticky;
  /* ⚠️ A measured constant, not var(--lpen-sticky-top). The header sets that
     variable on #lpen-hdr, so it never reaches a page's own sections (§18o).
     77px is the scrolled header bar. */
  /* ⚠️ 0, NOT 77. THE SITE HEADER DOES NOT ACTUALLY STICK.
     It declares `position: sticky; top: 32px`, but its containing block is
     the `<header class="elementor elementor-49373">` wrapper, which is
     `position: static` and only 67px tall. A sticky element cannot travel
     outside its containing block, so the header has nothing to travel in and
     scrolls away like any other element.

     Measured on this page AND on /faq/ on 2026-08-26: at scrollY 2446 the
     header's top was -2414. This is a live site-wide defect, not something
     this page causes, and §18c is written as though the header sticks.
     Reported; not fixed here, because it belongs to header/build_header.py.

     So the band clears nothing and goes to the top of the window. If the
     header is ever repaired, this constant becomes 77 again (or 65 in its
     scrolled state) and z-index 30 keeps the band behind it in the meantime. */
  top: 0;
  z-index: 30;
  border-bottom: 3px solid var(--l21-gold-500);
  box-shadow: 0 6px 18px rgba(1, 32, 50, 0.18);
}

/* ⚠️ Logged-in only. WordPress fixes a 32px admin bar over the viewport, so
   without this the band sits behind it for anyone signed in. Visitors are
   unaffected. The class is WordPress's own, so this needs no JS. Below 600px
   WordPress stops fixing the admin bar, and the band is static below 768px
   anyway, so the two never disagree. */
body.admin-bar #lpen-l21-notice {
  top: 32px;
}

/* ⚠️ Elementor gives every container 10px of padding by default, and this
   band nests two rows inside the section. 40px of it in a component whose
   whole requirement is "not too much height" is most of the budget. */
#lpen-l21-notice .e-con {
  padding-top: 0;
  padding-bottom: 0;
}

/* ⚠️ THE BUTTONS SIZE TO THEIR LABELS; THE COPY ABSORBS WHAT IS LEFT.
   The first version pinned the copy to 52% and the buttons to 46%, and both
   labels were clipped: `white-space: nowrap` in a column narrower than the
   text pushes the label straight out of its own button box. The measured
   widths looked fine, because the BOX fitted and the text did not.

   This is also the only version that survives 25 courses with 25 different
   link labels, which is what this builder is for. `min-width: 0` is what
   lets the copy column actually shrink; without it a flex item refuses to go
   below its content width and the buttons get squeezed again. */
#lpen-l21-optcopy {
  flex: 1 1 auto;
  min-width: 0;
}

/* ⚠️ `width: auto` is load-bearing. Every `.e-con` carries `width: 100%`
   (§18l), so `flex: 0 0 auto` resolves its basis to the FULL ROW: the buttons
   took all 1120px and the copy column collapsed to 20px, one word per line.
   `flex: 0 0 auto` alone is not "size to content" on an Elementor container. */
#lpen-l21-optbtns {
  flex: 0 0 auto;
  width: auto;
}

#lpen-l21-notice .elementor-widget-button .elementor-button {
  white-space: nowrap;
}

/* Below 768px the band stacks, so it stops being slim: two lines of copy and
   two full width buttons is about 190px, and a sticky 190px under a sticky
   header on a 640px screen leaves a third of the viewport for the page.

   ⚠️ So it is STATIC on a phone. It still sits directly under the hero, which
   is the first thing a visitor reads, and that is where this message does its
   work. Sticky is a desktop affordance here, not a promise. */
@media (max-width: 767px) {
  #lpen-l21-notice {
    position: static;
    box-shadow: none;
  }

  #lpen-l21-notice .elementor-widget-button .elementor-button {
    width: 100%;
    justify-content: center;
    white-space: normal;
  }

  #lpen-l21-optbtns {
    width: 100%;
  }
}

/* ------------------------------------------------- 8 focus and motion */
/* §3.2. The purple ring is the one colour on the site that cannot be confused
   with a brand state, and it has to beat LearnDash and the theme, both of
   which set box-shadow: none on links. */
#lpen-l21-hero a:focus-visible,
#lpen-l21-notice a:focus-visible,
#lpen-l21-body a:focus-visible,
#lpen-l21-body button:focus-visible {
  outline: 3px solid var(--l21-focus);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ⚠️ Kill the motion, not the transform. §18c records a reduced-motion block
   that reset `transform: none` on every descendant and so parked the site's
   skip link permanently on screen, because that transform was doing layout
   rather than animation. Only transitions are switched off here. */
@media (prefers-reduced-motion: reduce) {
  #lpen-l21-hero *,
  #lpen-l21-notice *,
  #lpen-l21-body * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ====== GENERATED: DO NOT EDIT ====== */
/* Headshot focal points, from FACULTY[].focus */
#lpen-l21-fac .lpen-l21-face--andrew-carvajal img{object-position:50% 22%}
#lpen-l21-fac .lpen-l21-face--chantal-desloges img{object-position:50% 16%}
