/* ============================================================================
 * homecards.css — the recipe deck on the front door (js/homecards.js).
 *
 * EVERY class here is prefixed `hc-`. Nothing in this file styles an existing
 * app class, so it cannot reach any other screen, and js/homecards.js is the
 * only thing that renders these names.
 *
 * THE SIZES ARE THE DESIGN, so they are stated once here rather than in JS:
 *   · a card is 86% of the rail on a phone, so the NEXT card always shows —
 *     ~38px of it at 375px, ~30px at 320px. A carousel that looks like a single
 *     panel is one nobody swipes.
 *   · two cards from 680px, three from 1000px, and a peek at every width. There
 *     is no reason to hide cards on a screen that can show them.
 *   · every control is a real button, and mobile.css's 44px floor applies to all
 *     of them. The phone's pager dots are deliberately NOT buttons — nine dots
 *     18px apart cannot have honest 44px targets, so they indicate and the two
 *     arrows beside them control.
 *
 * Scrolling, snapping and momentum are the browser's (scroll-snap), not a
 * script's: it costs nothing per frame on a cheap Android and it can never fight
 * the page's own vertical scroll, because the compositor locks the axis.
 * ==========================================================================*/

.hc { margin: 0 2px 22px; }

.hc-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; }
.hc-h { font-size: 16px; font-weight: 800; color: var(--ink); margin: 0; line-height: 1.25; }

/* ---- the line above the deck: the three states --------------------------- */

/* A brand-new school. The biggest thing on the screen, because it is the best
   chance the product gets to explain itself. */
.hc-start {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: color-mix(in srgb, var(--brand) 8%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--brand) 34%, var(--line));
  border-radius: 14px; padding: 14px 15px; margin: 0 0 12px;
}
.hc-start-tx { flex: 1 1 240px; min-width: 0; }
.hc-start-t { display: block; font-size: 16px; font-weight: 800; color: var(--ink); }
.hc-start-s { display: block; font-size: 13px; color: var(--ink-soft); margin-top: 3px; line-height: 1.4; }
.hc-start-b { flex: 0 0 auto; }

/* Half set up, and fully set up. One quiet line either way. */
.hc-next {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 9px 12px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
}
.hc-next-t { font-size: 13px; font-weight: 600; color: var(--ink); }
.hc-unused { display: flex; gap: 6px; flex-wrap: wrap; }

/* ---- the rail ------------------------------------------------------------ */

.hc-rail {
  position: relative;                 /* card.offsetLeft is read against this */
  display: flex; align-items: stretch; gap: 12px;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;     /* a horizontal overscroll is not "go back" */
  -webkit-overflow-scrolling: touch;
  /* ROOM INSIDE THE CLIP FOR THE CARD'S OWN SHADOW.
     REPORTED: "the shadows are all truncated" — the panel's soft shadow was cut
     dead straight along the top and the bottom, most visibly at the top-left
     corner and as a band under the deck.

     A HORIZONTAL SCROLL CONTAINER CANNOT HELP CLIPPING VERTICALLY. Set
     overflow-x to auto and the other axis computes to auto too, whatever it
     says — `visible` is not available on one axis alone. So the rail was always
     going to cut anything that overflowed it, and at 2px/10px there was nowhere
     near enough room: the neu panel's shadow (--nu-3) reaches about 23px above
     its box and 29px below, from an 11px offset on a 24px blur and a 14px
     offset on a 30px blur.
     MEASURED, not chosen: those two numbers are the offsets plus half the blurs
     the skin actually declares, so the padding follows the shadow rather than
     the shadow having to fit the padding.

     THE NEGATIVE MARGIN GIVES THE SPACE BACK, so nothing on the page moves. The
     area it reclaims holds only a translucent shadow, which is exactly the kind
     of thing that should overlap its neighbours. */
  padding: 24px 0 30px;
  margin: -22px 0 -20px;
}
/* Dragged with a mouse: the pointer says so, and text must not select under it. */
.hc-rail.hc-dragging { cursor: grabbing; user-select: none; -webkit-user-select: none; }
.hc-rail.hc-dragging .hc-card { cursor: grabbing; }
/* A STRAY `}` USED TO SIT HERE, closing nothing — every brace above it already
   balanced. A lone closing brace at the top level is a parse error, and the
   browser recovers by throwing away the rule that FOLLOWS it. What followed it
   was the scrollbar block, so the phone's `.hc-m .hc-rail { scrollbar-width:
   none }` never applied either: the one thing those rules existed to do was the
   one thing they could not do, and nothing looked broken enough to question.
   MEASURED: with the brace present, `.hc-rail{scrollbar-width:none}` was absent
   from the CSSOM entirely while the file itself clearly contained it. */

/* NO SCROLLBAR, ON ANY SCREEN. This used to keep a slim 8px bar on desktop, on
   the argument that it says "there is more" to somebody who will never swipe.
   In place it did not read as an affordance — it read as a stray grey line
   under a soft card, in a design where nothing else has one. The deck already
   says there is more three times over: the ‹ › arrows, the row of dots, and the
   "1 of 7" counter, all of which are real controls rather than a hint. */
.hc-rail { scrollbar-width: none; -ms-overflow-style: none; }
.hc-rail::-webkit-scrollbar { display: none; width: 0; height: 0; }

/* ---- one card ------------------------------------------------------------ */

/* HALF A PAGE, NOT A THIRD OF ONE. 340px was three cramped columns on a laptop
   and the trees had to squeeze; the owner asked for one full or half page with
   room to breathe. A card is now up to 560px \u2014 two on a wide screen, one and a
   peek on a narrow one, and the peek is what tells a reader to swipe. */
/* ONE CARD, ONE PAGE. 560px was still narrow enough that five or seven children
   wrapped onto two and three rows \u2014 and a wrapped row is what pushed the trunk
   line down THROUGH the nodes below it, which looked broken because it was. At
   full width the children fit on one line and the diagram is a diagram again.
   The pager underneath (\u2039 \u203a and the dots) is what says there is more; a sliver
   of the next card would only reintroduce the crowding this fixes. */
/* THE PAGE. Full width because that is what the rail snaps to, and nothing
   else " no box, no padding, no background. What is drawn is .hc-panel. */
.hc-card {
  flex: 0 0 100%; max-width: none;
  scroll-snap-align: start;
  display: flex; flex-direction: column;
  outline: none;
}
/* THE BOX, AND IT IS ONLY AS WIDE AS THE DIAGRAM IN IT. `fit-content` resolves
   against the tree's max-content width, and the rows are nowrap, so that is
   exactly the nodes plus their gaps " a three-node card draws a three-node box.
   max-width keeps a seven-node card inside the page it has. */
.hc-panel {
  width: fit-content; max-width: 100%; margin: 0 auto;
  /* IT TAKES THE CARD'S FULL HEIGHT and centres what is in it. Every card
     in the rail shares one height, and a rail of different-height boxes
     reads as broken — the rule further down says so and it is right.
     Letting the panel be content-height held on a desktop by luck (every
     tree is 242px there) and fell apart on a phone, where the rows wrap:
     measured at 375px, seven panels came out 389, 306, 472, 555, 389, 374
     and 374px tall. So the WIDTH hugs the diagram and the HEIGHT does not,
     and the vertical slack is centred here rather than on the card. */
  flex: 1 1 auto; justify-content: center;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 16px;
  padding: 14px;
}
.hc-card:focus-visible .hc-panel { box-shadow: inset 0 0 0 2px var(--brand); }
.hc-card-wait .hc-panel { background: var(--panel); border-style: dashed; }

.hc-c-title {
  font-size: 14px; font-weight: 800; color: var(--ink); margin: 0 0 2px;
  line-height: 1.25; text-align: center; overflow-wrap: anywhere;
}

/* ==========================================================================
 * THE TREE
 *
 * Two rows and the space between them. Inputs on top, outputs underneath, the
 * lines drawn into an <svg> that fills the whole box and sits behind both rows.
 *
 * The svg is absolutely positioned and z-index 0 so the rows keep their normal
 * flow \2014 the layout decides where the nodes go, and the drawing follows the
 * layout, never the other way round. That ordering is what lets a node wrap to a
 * second line on a narrow phone without the diagram falling apart: the branches
 * are measured after the wrap has happened.
 *
 * min-height on the gap between the rows is the one magic number here. It is the
 * room the fan needs to look like a fan rather than a squeeze, and it is set in
 * ch units so it scales with the reader's own font size.
 * ======================================================================== */
/* The tree sits at the TOP of the card and does not stretch to fill it. flex:1
   made every card as tall as the tallest — nine cards deep, that is a column of
   empty white under a small diagram, and the deck looked broken rather than
   sparse. The rail gives all cards one height; the tree just does not have to
   use it. */
.hc-tree { position: relative; display: flex; flex-direction: column; gap: 54px; padding: 10px 2px 2px; align-self: stretch; width: 100%; }
.hc-wires { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; overflow: visible; }
.hc-wire { stroke: var(--line-strong); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.hc-wire-trunk { stroke: color-mix(in srgb, var(--brand) 55%, var(--line-strong)); stroke-width: 2; }
@keyframes hcDraw { to { stroke-dashoffset: 0; } }

/* ONE LINE. nowrap is the whole point of the wider card: seven children across
   one row read as one set, where the same seven over three rows read as a grid
   with a line drawn on it. */
.hc-row { position: relative; z-index: 1; display: flex; flex-wrap: nowrap; justify-content: center; gap: 14px; }
/* A PHONE CANNOT HAVE ONE ROW OF SEVEN, so it wraps there and only there. The
   line-drawing code groups nodes by the row they actually landed on, so a wrapped
   row still gets its own fan off the trunk \u2014 that was fixed in 1.0.143 and is
   what makes this media query safe rather than a regression in miniature. */
@media (max-width: 760px) {
  .hc-row { flex-wrap: wrap; gap: 12px 10px; }
  /* AND THE BOX STOPS HUGGING, because there is nothing left to hug: a
     wrapped row already fills the width it is given, so fit-content just
     lands wherever the last row happened to break. Measured at 375px: six
     panels came out 351px wide and one 309px, which on a phone is a page
     that visibly narrows as you swipe past it. */
  /* margin AND width. An auto cross-axis margin switches OFF the flex
     stretch, so `width: auto` on its own still shrink-wrapped and the
     309px page stayed 309px. */
  .hc-panel { width: auto; margin: 0; align-self: stretch; }
}
.hc-row-out { gap: 10px; }

/* ---- one node ------------------------------------------------------------
 * Inputs and outputs share a shape deliberately: what distinguishes them is the
 * row and the direction of the line, not two visual languages. The input row is
 * filled (it is a thing the school HAS) and the output row is outlined (it is a
 * thing the school can GO to), which is the smallest difference that still reads
 * at a glance.
 *
 * 44px minimum on both axes because every node is a tap target on a phone, and
 * a diagram you cannot reliably tap is a picture of an app rather than an app.
 * ------------------------------------------------------------------------ */
.hc-n {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; min-width: 112px; min-height: 88px; padding: 12px 14px;
  border-radius: 13px; border: 1px solid var(--line); background: var(--panel-2);
  font: inherit; color: var(--ink); text-align: center; cursor: default;
  position: relative;
  animation: hcPop .32s cubic-bezier(.2,.9,.3,1.3) backwards;
}
button.hc-n { cursor: pointer; transition: transform .14s ease, border-color .14s ease, background .14s ease; }
button.hc-n:hover { transform: translateY(-2px); border-color: var(--brand); background: color-mix(in srgb, var(--brand) 8%, var(--panel-2)); }
button.hc-n:active { transform: translateY(0); }
.hc-n:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }

.hc-n-ic { font-size: 27px; line-height: 1; }
.hc-n-l { font-size: 13.5px; font-weight: 700; line-height: 1.15; letter-spacing: -.01em; }

/* The input row carries the weight: these are the things without which the row
   below is empty. */
.hc-n-in { background: color-mix(in srgb, var(--brand) 9%, var(--panel-2)); border-color: color-mix(in srgb, var(--brand) 28%, var(--line)); }
.hc-n-out { background: var(--panel); }

/* Dimmed = not there yet. It is never disabled: an output still opens its own
   page, which says for itself what it needs, and a missing input is a button
   that goes and gets it. Dimming says "not yet", it does not lock a door. */
.hc-n-dim { opacity: .55; border-style: dashed; }
button.hc-n-dim:hover { opacity: 1; }

/* The tick, and the plus that invites the tap. Corner-mounted so the label keeps
   the middle of the node and every node stays the same size whether or not it
   carries a mark. */
.hc-n-mk {
  position: absolute; top: -5px; right: -5px;
  width: 17px; height: 17px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 900; line-height: 1;
  border: 2px solid var(--panel);
}
/* --on-fill, not #fff: the fill under this text is a THEMED token, and in
   dark mode it is a bright colour, where white text measured ~2.1-2.5:1.
   --on-fill is #fff in light and near-black in dark, so this pairing stays
   AA in both without the rule needing to know which theme is running. */
.hc-n-mk-on { background: var(--good); color: var(--on-fill); }
.hc-n-mk-off { background: var(--line-strong); color: var(--panel); }
/* …AND THAT RULE WAS BEING OVERRIDDEN, so the tick was not on screen at all.
   homecards.js:240 builds this badge with a lone '✓', and App.h hands a lone UI
   glyph to icons.js, which swaps it for a Lucide <svg> AND sets an inline
   `style="color: color-mix(in srgb, #0f9d78 72%, var(--ink))"`. An inline style
   beats a class rule, so the check was painted green on the green disc:
   MEASURED at 1.1:1, on six badges on the front door of the app.

   Only !important beats an inline style, which makes this one of the few places
   it is the right tool rather than a shortcut. `currentColor` rather than the
   token written out a third time, so the swapped glyph inherits whichever of
   the two rules above already applies — one owner for the badge's ink. */
.hc-n-mk .lu { color: currentColor !important; width: 11px; height: 11px; }

@keyframes hcPop { from { opacity: 0; transform: translateY(6px) scale(.94); } to { opacity: 1; transform: none; } }
/* Stagger, so the tree assembles top-down instead of appearing all at once. */
.hc-row-in .hc-n:nth-child(1) { animation-delay: .02s; }
.hc-row-in .hc-n:nth-child(2) { animation-delay: .07s; }
.hc-row-in .hc-n:nth-child(3) { animation-delay: .12s; }
.hc-row-out .hc-n:nth-child(1) { animation-delay: .30s; }
.hc-row-out .hc-n:nth-child(2) { animation-delay: .36s; }
.hc-row-out .hc-n:nth-child(3) { animation-delay: .42s; }
.hc-row-out .hc-n:nth-child(4) { animation-delay: .48s; }
.hc-row-out .hc-n:nth-child(5) { animation-delay: .54s; }

/* Stillness when it is asked for. The lines are drawn instantly instead of
   walking out (js side checks the same query), and nothing pops. */
@media (prefers-reduced-motion: reduce) {
  .hc-n { animation: none; }
  button.hc-n:hover { transform: none; }
}

/* ---- the pager ----------------------------------------------------------- */

.hc-pager { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 2px 0 0; }
.hc-arrow {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  font-size: 20px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.hc-arrow:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.hc-arrow:disabled { opacity: .35; cursor: default; }
.hc-arrow:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.hc-m .hc-arrow { width: 44px; height: 44px; }

.hc-dots { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; justify-content: center; min-width: 0; }
.hc-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--line-strong); border: none; padding: 0;
}
button.hc-dot { cursor: pointer; }
.hc-dot.on { background: var(--brand); transform: scale(1.35); }
button.hc-dot { position: relative; }
button.hc-dot::after { content: ''; position: absolute; inset: -6px; }
button.hc-dot:focus-visible { outline: 3px solid var(--brand); outline-offset: 4px; }
.hc-count { font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- "or go straight to" — the old thirteen doors, still one tap ---------- */

.hc-all-lbl { margin: 16px 0 8px; }
.hc-all { display: flex; flex-wrap: wrap; gap: 7px; }
.hc-chip {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 13px; font-weight: 600; color: var(--ink); cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 13px; min-height: 40px;
}
/* THE KIT'S 16px IS FOR A PAGE ACTION, NOT FOR THIRTEEN SHORTCUTS.
   mobile.css puts `font-size: 16px` on every <button> — the right floor for a
   control you press once, and the wrong one here: at 16px a chip is wider than
   half a 375px rail, so the strip came out as ELEVEN near-full-width rows
   (measured), 554px tall, which pushed every one of the thirteen destinations
   the tiles used to offer ~300px further down the page than they were. Two
   classes beat one class + one element, so this wins without !important — and
   it touches the LABEL only. The 44px hit area the kit gives these is untouched
   and is still what a thumb lands on. */
.hc-m .hc-chip { font-size: 14px; }
.hc-chip:hover { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 7%, var(--panel)); }
.hc-chip:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.hc-chip-ic { flex: 0 0 auto; font-size: 15px; display: inline-flex; align-items: center; }
.hc-chip-ic svg, .hc-chip-ic .lu { width: 17px; height: 17px; }
.hc-chip-l { white-space: nowrap; }

/* ---- widths: a peek at every size ---------------------------------------- */

/* THESE TWO USED TO SET THE CARD WIDTH AND THEY WON, SILENTLY.
   The base rule was changed to one card per screen; these came later in the file
   and put it back to 46% and then 30%, so a laptop still showed three narrow
   cards and the children still wrapped. The base rule is now the only thing that
   sizes a card, and the wide breakpoint keeps only what it was really for \u2014 a
   slightly larger heading. */
@media (min-width: 1000px) {
  .hc-h { font-size: 17px; }
}
/* 320px is the narrowest phone still in service in Mizoram. The card gives back
   a little width so the peek survives, and the padding tightens so the content
   does not. */
@media (max-width: 340px) {
  .hc-card { padding: 12px; }   /* width comes from the base rule; only the padding tightens */
  .hc-chip { padding: 8px 11px; font-size: 12.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .hc-rail { scroll-behavior: auto; }
  .hc-out { transition: none; }
  .hc-dot.on { transform: none; outline: 2px solid var(--brand); outline-offset: 2px; }
}


/* ---- the one-liner under each tree --------------------------------------- */
.hc-desc {
  margin: 18px 4px 2px; text-align: center;
  font-size: 12.5px; line-height: 1.45; color: var(--ink-soft);
  max-width: 46ch; margin-left: auto; margin-right: auto;
}

/* ---- WHERE THE SLACK GOES ------------------------------------------------
   Every card in the deck shares one height — they sit in a scrolling rail, and
   a rail of different-height cards reads as broken. That height is set by the
   TALLEST tree: eight nodes, 310px. The smallest is four nodes at 227px, and
   all of the difference was landing at the bottom. Measured on the demo: 87 to
   105px of empty card under the caption, with the diagram pressed against the
   heading above it. A small tree did not read as a small diagram; it read as a
   large card that had failed to finish loading.

   The diagram and its caption sit in the MIDDLE of the card instead, so a
   four-node card reads as a small thing with room around it rather than a large
   thing that failed to load. The tallest card has no slack to share and is
   untouched (measured: 47/47, 56/56, 56/56, 14/14 above/below).

   justify-content, not a pair of auto margins. Two `margin: auto` flex items are
   supposed to split the free space evenly and here they did not — measured 65px
   above and 8px below, which is the orphaned caption again in a different place.
   One property that centres the whole group cannot drift. */
.hc-card { justify-content: center; }

/* ---- and the same slack, sideways ----------------------------------------
   The rule above gave the vertical slack somewhere sensible to go. The
   horizontal slack had nowhere: every card drew a box the full width of the
   rail, so a card with three children showed 630px of empty panel beside a
   356px diagram. .hc-panel above is that fix " the box is the diagram's width,
   the page around it is empty page rather than empty box.

   THE CAPTION MUST NOT DECIDE THE WIDTH. It is centred prose under the
   diagram, and letting a long one stretch the box would put the panel's edge
   somewhere the diagram has no relationship to. 46ch already caps it; this
   stops it setting the floor. */
.hc-panel > .hc-desc { width: 0; min-width: 100%; }
/* AND IT RESERVES ITS SECOND LINE WHETHER IT USES IT OR NOT. Measured:
   six captions in this deck fit on one line and one does not, so that card
   drew a box 18px taller than the rest and the diagram sat 9px higher
   (the card centres its contents). Paging visibly jogged. Any caption can
   wrap on a narrower screen, so the room is kept rather than the copy
   trimmed to fit a width nobody promised. */
.hc-desc { min-height: 2.9em; }
