/* ==========================================================================
   lessons-home.css - lesson list (hero, cards) and the lesson reader shell.
   ========================================================================== */

.python-lesson-card:focus-visible {
  outline: 5px solid var(--primary);
  outline-offset: 5px;
}

/* The container inside owns the full viewport height, so the view adds none. */
.python-lesson-view {
  padding-block: 0;
}

.python-lesson-view > .container {
  width: min(97%, 1600px);
  max-width: 1600px;
}

/* The shell's own chrome, and the page-level towers, while a lesson is open.
   The second selector in each pair is the same thing for a load that opens
   straight into the reader: `lesson-reader-active` is a class on <body>, which
   showView cannot add until the router is awake, so on a refresh inside a
   lesson the header and the footer both painted first and
   vanished a beat later. The attribute is on <html> and is set before the
   first paint. */
/* The crests go with the footer they break onto. Left behind, they were the
   one piece of the home page still in the flow while a lesson is open, and
   the height they took is height the shell could be scrolled by — behind a
   reader that is supposed to be the only thing that scrolls. */
.lesson-reader-active .main-footer,
html[data-boot-view="reader"] .main-footer {
  display: none;
}

/* The header no longer goes away while a lesson is open, and that reversal is
   the whole point of the island.

   It used to vanish because there were two bars and only one of them was any
   use in here: the shell's said "marwandahi" and the reader's said which part
   you were standing in, so the shell's was the one that left. There is one bar
   now. It is the same object on all three screens and it carries the lesson's
   own gear while a lesson is open — which is exactly what the reader's bar was
   doing, from inside a frame that could not draw a drawer without clipping it.

   The rail stays fixed above the frame, so the reader is still the only thing
   that scrolls; see the island's geometry contract in css/island.css. */
/* Desktop only, and the media query is the whole point of it.

   Docking the plate to the bottom of a phone is css/island.css's rule, on a
   plain `.main-header` inside a max-width query. This one is
   `.lesson-reader-active .main-header` — two classes to its one — so written
   unguarded it won the cascade on every phone and dragged the island back to
   the top of the screen the moment a lesson opened. The dock is the phone's
   answer on all three screens or it is not an answer. */
@media (min-width: 721px) {
  .lesson-reader-active .main-header,
  html[data-boot-view="reader"] .main-header {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    /* Above the edge tab: both are fixed, both were 120, and at equal depth
       the later element in the document wins — which put the tab over an open
       drawer. */
    z-index: 130;
    /* The rail is only a rail: the plate inside it takes the presses, and
       everything either side of it belongs to the lesson underneath. */
    pointer-events: none;
  }

  .lesson-reader-active .main-header .island,
  html[data-boot-view="reader"] .main-header .island {
    pointer-events: auto;
  }
}

/* The frame starts under the rail rather than behind it.

   The rail is fixed while a lesson is open, so it is out of the flow and the
   column would otherwise begin at the top of the screen with the plate lying
   over its first 82px. Padding on the column rather than a smaller height,
   because the column is `height: 100dvh` under `box-sizing: border-box` —
   which means padding comes out of the 100dvh rather than adding to it, and
   the frame, which takes whatever the column has left, gives up exactly the
   rail and nothing else. Shrinking the height instead left the padding's
   worth of dead paper below the frame, since the column was already starting
   at zero.

   On a phone --header-h is down to the notch inset — the plate is docked at
   the bottom by then — so this lands on nothing and needs no second rule. The
   frame's own bottom clearance there is the lesson's own, in
   css/python-reader-features.css under `is-shelled`. */
/* Superseded: the column no longer stands the frame under the rail.

   The rail was a band of the shell's own paper across the top of the screen
   with the plate floating in it, and the lesson began below it — so the top
   of every lesson was a strip of somewhere else, and the plate read as an
   object outside the page rather than one lying on it. The frame is the whole
   viewport now and the plate floats over it; the room under the plate is left
   by the lesson, from the inside, in css/python-reader-features.css under
   `is-shelled`. */

/* The shell's paper texture has to go while a lesson is open. Both layers are
   painted by the shell, on top of the iframe, and being outside that document
   they are outside the reach of the lesson's own `backdrop-filter` — so the
   dots rode straight over the reader's glass dock instead of being blurred by
   it, and the pill read as a hole in the page. The lesson draws its own dot
   field anyway, so nothing is lost by dropping the shell's copy here.
   (Only light mode ever showed it: --bg-dots is 3% alpha in the dark theme.) */
.lesson-reader-active .halftone-bg,
.lesson-reader-active .manga-grid-overlay,
html[data-boot-view="reader"] .halftone-bg,
html[data-boot-view="reader"] .manga-grid-overlay {
  display: none;
}


.python-lessons-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--spacing-xl);
}

/* The lesson card
   ------------------------------------------------------------------------
   Four plates off the same chart. A sea chart's index prints each sheet as a
   numbered panel — a number in a box, what the sheet covers, and the scale it
   is drawn at — and that is exactly the job these four do for the course, in
   an order the reader actually takes. So they are drawn as plates: ruled in
   the sea's own line, numbered in the corner the way a sheet is, and with the
   lesson's glyph engraved across them.

   The foot is a block of deep water, not of ink. It names the action and
   carries the measure of how much of the lesson is behind you at the same
   time. */
.python-lesson-card {
  position: relative;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  min-width: 0;
  overflow: hidden;
  color: var(--text-primary);
  background: var(--bg-secondary);
  /* Ruled in the water, not in ink. Four black frames on a pale chart were the
     loudest thing on the page and the only part of it still drawn in the old
     palette. */
  border: 3px solid var(--card-foot);
  border-radius: var(--radius-md);
  box-shadow: 6px 6px 0 color-mix(in srgb, var(--shadow-color) 24%, transparent);
  font: inherit;
  text-align: start;
  /* The card is an <a> now, so the browser would underline every word in it
     and paint the lot in the link colour. It reads as a card either way; the
     only thing the element type changes is that the URL is finally reachable. */
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--transition-normal), box-shadow var(--transition-normal), border-color var(--transition-fast);
}

.python-lesson-card:hover {
  transform: translate(-4px, -4px);
  border-color: var(--accent-yellow);
  box-shadow: 10px 10px 0 color-mix(in srgb, var(--shadow-color) 30%, transparent);
}

/* ---------------------------------------------------------------- artwork */

/* Bled off the far edge, at a weight that reads as a printed mark rather than
   as text somebody forgot to size. It sits under everything and is never
   read: the glyph is aria-hidden, and the lesson's name is right beside it.

   `direction: ltr` is not decoration here — three of these four marks are
   mirrored by the bidi algorithm in an RTL line, and `<-` came out as `->`.
   It also settles which edge the offsets below mean: the glyph's own inline
   start is the physical left, which is the edge the Arabic text runs away
   from. */
.python-lesson-glyph {
  position: absolute;
  z-index: 0;
  inset-block-start: 50%;
  inset-inline-start: -0.3em;
  /* Outlined, not filled. A solid pale glyph is a smudge on the paper; drawn
     as a hairline it is the same kind of mark as the depth contours running
     underneath it — engraved on the plate rather than printed over it. The
     fill is transparent, so the stroke is the whole of the letter. */
  color: transparent;
  -webkit-text-stroke: 2.5px color-mix(in srgb, var(--primary) 34%, transparent);
  opacity: 1;
  font-family: var(--font-mono);
  font-size: clamp(6.5rem, 15vw, 10.5rem);
  font-weight: 600;
  line-height: 0.78;
  letter-spacing: -0.06em;
  direction: ltr;
  white-space: nowrap;
  pointer-events: none;
  transform: translateY(-58%);
  transition: opacity var(--transition-normal), transform var(--transition-normal);
}

/* The alternation is gone. It printed every second glyph in the yellow, which
   on warm paper was a second ink and on this pale blue one is a beige smear —
   and the four marks are `>`, `]`, `|||` and `<`, which tell each other apart
   by shape without needing a colour to do it. One ink, one weight: an
   engraving on a plate, which is what it is. */
.python-lesson-card:hover .python-lesson-glyph {
  -webkit-text-stroke-color: rgba(233, 180, 76, 0.62);
  transform: translateY(-58%) translateX(-0.05em);
}

/* ------------------------------------------------------------------- body */

.python-lesson-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  min-width: 0;
  min-height: 14rem;
  padding: var(--spacing-xl);
}

/* The sheet number, boxed the way a chart's index boxes it. It was a muted
   mono figure floating at the corner, which is a caption; ruled, it is a
   label — and the rule is what makes four of them read as a set. */
.python-lesson-index {
  padding: 0.1rem 0.5rem;
  color: var(--primary);
  border: 1.5px solid color-mix(in srgb, var(--primary) 42%, transparent);
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.python-lesson-card:hover .python-lesson-index {
  color: var(--card-foot);
  border-color: var(--accent-yellow);
}

.python-lesson-body strong {
  min-width: 0;
  color: var(--primary);
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3.4vw, 1.75rem);
  font-weight: 900;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.python-lesson-body small {
  max-width: 34ch;
  color: var(--text-secondary);
  font-size: 0.88rem;
  line-height: 1.75;
  text-wrap: pretty;
}

.python-lesson-body small code {
  padding: 0.05em 0.3em;
  color: var(--primary-on-light);
  background: var(--primary-light);
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.92em;
}

/* The three views the lesson opens with, named once and in the order the
   reader's own switch puts them in. As a line rather than three outlined
   pills: the artwork is the loud thing on this card, and pills here were three
   more boxes competing with it for a job a line of type does. */
.python-lesson-parts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.75rem;
  margin-block-start: auto;
  padding-block-start: var(--spacing-md);
  /* Off the muted ink. This is the line that answers "what do I get", and it
     was the smallest and faintest type on the card — it cleared the bar and
     nothing more. The separators carry the lightness now instead of the
     words. */
  color: var(--text-secondary);
  font-size: 0.78rem;
  font-weight: 700;
}

.python-lesson-parts i {
  display: flex;
  gap: 0.75rem;
  font-style: normal;
}

.python-lesson-parts i::before {
  content: "·";
  opacity: 0.42;
}

/* -------------------------------------------------------------- the foot */

/* One block of ink across the bottom of the card, doing two jobs. It names the
   action, and it carries the measure of how much of the lesson is behind you —
   the site knew that all along and never said it anywhere you could see it
   without opening the lesson first. */
.python-lesson-action {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding: 0.85rem var(--spacing-xl);
  color: var(--card-foot-ink);
  background: var(--card-foot);
  font-size: 0.95rem;
  font-weight: 800;
  transition: background-color var(--transition-normal), color var(--transition-normal);
}

/* After dark the slab inverts, which --card-foot already carries: at night a
   block of deep water on a near-black page is not a block of anything, so the
   foot becomes the light slab a solid block of ink is after dark. Not pure
   white — four of these across a dark page at #fff glare.

   */
[data-theme="dark"] .python-lesson-readout {
  color: #0b2e4f;
}

/* Reaching for the card inks the foot in the card's own colour. It is the only
   solid block on the page that changes ground on hover, which is what makes it
   read as the thing you are about to press rather than a caption under a
   picture. */
/* Reaching for the card lights the foot. One accent and one only — the gold
   off his coat, the same gold the hero's button is — so the thing you are
   about to press is the only warm mark on a page of water. */
.python-lesson-card:hover .python-lesson-action {
  color: #14100b;
  background: var(--accent-yellow);
}

/* The meter is a bar and needs a ground to be a bar against; the number is
   not, and giving it one painted a dark navy chip behind dark ink — the count
   disappeared on exactly the card you were reaching for. Lit, the foot is one
   block: the number takes the same ink as the label beside it and is told
   apart by its mono face and its place at the end of the row, which is how it
   was already being read. */
.python-lesson-card:hover .python-lesson-readout {
  color: #14100b;
}

.python-lesson-card:hover .python-lesson-meter {
  background: var(--card-foot);
}

.python-lesson-action b {
  flex: 0 0 auto;
  transition: transform var(--transition-normal);
}

.python-lesson-card:hover .python-lesson-action b {
  transform: translateX(-4px);
}

.python-lesson-readout {
  color: var(--accent-yellow);
  direction: ltr;
  font-family: var(--font-mono);
  font-size: 0.88rem;
  font-weight: 600;
  white-space: nowrap;
}

.python-lesson-readout[hidden] {
  display: none;
}

/* The measure itself: the hem of the ink block, filled as far as you have
   read. Contained to its own strip rather than filling the block behind the
   label, which would have put white type on orange for part of every card. */
.python-lesson-meter {
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  height: 7px;
  background: var(--accent-yellow);
  transition: width var(--transition-smooth);
}

.python-lesson-meter[hidden] {
  display: none;
}

.python-lesson-page-header[hidden] {
  display: none;
}

.python-lesson-page-header {
  display: flex;
  padding: 0.25rem 0;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
}

.python-lesson-page-header .study-volume-badge {
  padding: 0.3rem 0.85rem;
  font-size: 0.85rem;
}

.python-lesson-page-title {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

.python-lesson-page-title {
  justify-content: flex-end;
}

.python-lesson-page-title h2 {
  font-size: clamp(0.9rem, 1.6vw, 1.05rem);
  margin: 0;
}

/* The reader owns the whole screen: the container is the column, and the
   frame takes whatever the header above it did not. No fixed heights — they
   go stale the moment anything above the frame changes size. */
.python-lesson-view > .container {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

/* The frame is clipped to its own corners, so the lesson inside is rounded
   with it — enough to soften the box, not enough to start cutting into the
   text at the edges of a phone. */
.python-lesson-frame-shell {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: var(--bg-secondary);
  border: 3px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: 4px 4px 0 var(--shadow-color);
}

#lessonFrame {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--bg-primary);
  border: 0;
}

@media (max-width: 768px) {

/* One card at a time. Two columns on a phone leaves each plate about 150px of
   measure, which breaks "R Programming" across two lines and stands the three
   parts up in a column — the card stops being scannable, which is its whole
   job. */
.python-lessons-grid {
    grid-template-columns: minmax(0, 1fr);
  }

/* Stays one row on narrow screens: stacking it would spend a second row of
     a phone's screen on a title the badge already gives you. */
.python-lesson-page-header {
    align-items: center;
    gap: var(--spacing-sm);
  }

.python-lesson-page-title {
    justify-content: flex-start;
    min-width: 0;
  }

}

@media (max-width: 480px) {
.python-lesson-body {
    padding: var(--spacing-lg) var(--spacing-md);
  }

.python-lesson-action {
    padding-inline: var(--spacing-md);
  }

}

/* ==========================================================================
   Saved sections — the reading list, on the way to the lessons

   Written by renderSavedSections in js/app.js, and hidden entirely when nothing
   is saved. It sits above the four cards because it is the shorter road: a
   reader who has been here before wants the part they marked, not the lesson
   it is in. Someone arriving for the first time never sees it at all.
   ========================================================================== */

.saved-sections {
  margin-block-end: var(--spacing-xl);
  padding: var(--spacing-md) var(--spacing-md) var(--spacing-sm);
  background: var(--bg-secondary);
  border: 3px dashed var(--border-color);
  border-radius: var(--radius-md);
}

.saved-sections[hidden] {
  display: none;
}

.saved-sections-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--spacing-sm);
  margin-block-end: var(--spacing-sm);
}

.saved-sections-head h3 {
  margin: 0;
  color: var(--primary);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 900;
}

.saved-sections-count {
  color: var(--text-secondary);
  font-size: 0.78rem;
  font-weight: 800;
}

.saved-sections-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.saved-section {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.25rem;
  background: var(--bg-primary);
  border: 2px solid var(--border-light);
  border-radius: var(--radius-sm, 8px);
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.saved-section:hover {
  border-color: var(--primary);
  transform: translate(-2px, -2px);
}

.saved-section-go {
  display: grid;
  gap: 0.05rem;
  min-width: 0;
  padding: 0.45rem 0.6rem;
  text-decoration: none;
}

.saved-section-lesson {
  color: var(--text-secondary);
  font-size: 0.68rem;
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.saved-section-title {
  color: var(--text-primary);
  font-size: 0.85rem;
  font-weight: 800;
  line-height: 1.45;
}

.saved-section-drop {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  margin-inline-end: 0.25rem;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.saved-section-drop svg {
  width: 15px;
  height: 15px;
  fill: none;
}

.saved-section-drop:hover,
.saved-section-drop:focus-visible {
  color: var(--primary);
  background: var(--primary-light);
}

/* -------------------------------------------------- the reader is the screen

   The lesson used to be read through a window rather than on the page: the
   column kept the site's own gutters (min(97%, 1600px), plus the container's
   padding), and the frame inside it kept a card's chrome — a 3px rule, a
   large corner and a dropped shadow. That is right for a lesson card sitting
   in a grid of them. It is wrong for the thing itself: on a 1440 screen it
   spent 48px a side, a rule and a shadow on saying "this is a panel" to
   somebody who is not looking at a panel, they are reading. The measure the
   lesson wants is the lesson's own, set inside the frame, and every pixel the
   shell holds back is one the lesson cannot use for it.

   So while a lesson is open the column is the viewport and the frame is the
   column. The rail above it is untouched — it still owns --header-h, the
   frame still starts under it, and the reader is still the only thing that
   scrolls. What goes is only the framing, which was never load-bearing. */
.lesson-reader-active .python-lesson-view > .container,
html[data-boot-view="reader"] .python-lesson-view > .container {
  width: 100%;
  max-width: none;
  padding-inline: 0;
}

.lesson-reader-active .python-lesson-frame-shell,
html[data-boot-view="reader"] .python-lesson-frame-shell {
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
