/* ---------------------------------------------------------------------------
   Stellic Pathfinders — design tokens + app shell
   Values taken from Figma "Stellic FrontEnd Design", Page 4.
   --------------------------------------------------------------------------- */

/* Build B's two remaining Google faces: JetBrains Mono (all-caps micro labels)
   and Newsreader (the initials circles + the "of the degree" figure).
   Imported here rather than from each <head> so the brand lives in one file. */
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Newsreader:opsz,wght@6..72,400;6..72,500&display=swap');

/* The real "Pathfinder Hand" face, extracted from build B (assets/b/).
   ONE weight only — no 600/700 file exists, so any bold is synthesised. */
@font-face {
  font-family: 'Pathfinder Hand';
  src: url('../assets/b/PathfinderHand.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  /* surfaces */
  --bg:            #f6f2e9;
  --panel:         #faf8f1;
  --panel-alt:     #fdfbf6;
  --sidebar:       #fdfbf6;
  --sunken:        #f1ede2;
  --border:        #e5e0d7;
  --border-soft:   #ede7da;
  --placeholder:   #ded9d1;

  /* ink */
  --ink:           #1b1916;
  --ink-2:         #5c554a;
  --ink-3:         #8c8578;
  --ink-4:         #a9a192;

  /* accents */
  --accent:        #8c4535;
  --accent-tint:   #f0d9c8;
  --accent-soft:   #fbe9e4;
  --accent-line:   #e8c4b8;

  --green:         #5a7355;
  --green-tint:    #e6ece0;

  --amber:         #b8852e;
  --amber-tint:    #f2e0b8;
  --star:          #e0aa2e;

  --scroll-track:  #ede7da;
  --scroll-thumb:  #998c7a;

  /* course palette (Home / Profile schedule) */
  --c-cs:    #f2ded4;
  --c-math:  #dfe7dc;
  --c-phys:  #f2e6c4;
  --c-engl:  #f7dbe4;
  --c-psy:   #ecdcd4;

  /* type */
  --font-hand:  'Pathfinder Hand', 'Patrick Hand', 'Caveat', cursive;
  /* Build B's nav is 'Pathfinder Hand' (spec §navStyle). A shipped Caveat as a
     stand-in before the real face was extracted; the woff2 is now in
     assets/b/, so the nav uses the genuine article and Caveat is only a
     fallback for a failed font load. */
  --font-nav:   'Pathfinder Hand', 'Caveat', cursive;
  --font-body:  'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-serif: 'Playfair Display', Georgia, serif;
  /* build B tokens */
  --font-mono:      'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-newsreader:'Newsreader', Georgia, serif;

  /* elevation */
  --sh-1: 0 1px 4px rgba(0, 0, 0, .05);
  --sh-2: 0 2px 8px rgba(0, 0, 0, .06);
  --sh-3: 0 3px 10px rgba(0, 0, 0, .06);
  --sh-4: 0 6px 16px rgba(0, 0, 0, .10);
  --sh-5: 0 18px 48px rgba(0, 0, 0, .18);

  --sidebar-w: 217px;

  /* Colours that used to be written as literals, lifted into tokens so the NYU
     theme can reach them. Each default equals the literal it replaced, so the
     Flightplan theme renders exactly as before. */
  --rule: #e4ded0; --ink-b3: #8f8779; --dim: #b4ac9c; --accent-b: #a2593a;
  --accent-deep: #7e3f22; --accent-wash: #f1e3d8; --accent-wash-line: #dfc2ac;
  --ink-warm: #3a362f; --visa-bg: #f7edea; --visa-line: #e9d6ce;
  --dot-alert: #b4552f; --dot-warn: #96742e; --danger: #c0392b;
  --placeholder-ink: #9e998f; --divider-warm: #ede5db; --chip-bg: #f1ede4;
  --badge: #b7afa3; --title-ink: #000;
  --sch-math: #dde2d5; --sch-phys: #eee0ba; --sch-engl: #f2d3d8; --sch-psy: #e6d0c4;
  --sch-engl-ink: #994d66; --sch-phys-ink: #8c6b26; --sch-psy-ink: #805238;
  --fp-habits-bg: #fbf3e7; --fp-habits-line: #ead9b6; --fp-wins-bg: #fdfaf0; --fp-wins-line: #ede3c9;
  --fp-faint: #c3bba9; --fp-gold-ink: #7a5c1e; --fp-gold: #b49a5e; --fp-cream: #fffdf7;
  --fp-cal-dark: #6b665e; --fp-sage-line: #d7e0d0; --fp-off: #d9cfbb;
  --q-line: #e6cdb8; --q-box: #c9c0ae; --q-cream: #fffdf8; --q-x: #9a8f7d; --q-dot: #e2d9c9;
  --q-ink2: #736657; --q-ink: #242019; --q-edge: #3a352d; --q-radio: #b7a998;
  --q-dash: #c9bda9; --q-field: #cfc5b4;
  --font-initials: 'Pathfinder Hand', 'Newsreader', Georgia, serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* The Goals and Career-Plan boards sit on a dotted paper ground. */
body.paper {
  background-image: radial-gradient(var(--border) 1px, transparent 1px);
  background-size: 18px 18px;
  background-position: 6px 6px;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }
img { display: block; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* --- layout ---------------------------------------------------------------- */

.app { display: flex; min-height: 100vh; }

/* One canonical sidebar, identical on every page.
   Geometry from the Figma Home frame 388:1275. */

.sidebar {
  position: sticky;
  top: 0;
  align-self: flex-start;
  flex: 0 0 var(--sidebar-w);
  width: var(--sidebar-w);
  height: 100vh;
  background: var(--sidebar);
  border-right: 1px solid var(--border);
  padding: 32px 0 0;
  display: flex;
  flex-direction: column;
}

/* --- brand lockup (build B §3.2) -------------------------------------------
   Rock, wordmark and tagline, left-aligned on A's 34px sidebar inset.       */
.sidebar__brand { padding: 0 34px 24px; }

/* The brand rock. Native 600×554; drawn at B's sidebar size, 40×37, which is
   the same 1.0830 ratio (600/554 = 1.0830, 40/37 = 1.0811). */
.sidebar__mark {
  display: block;
  width: 40px; height: 37px;
  margin: 0 0 12px;
  object-fit: contain;
}

.sidebar__title {
  font-family: var(--font-hand);
  font-weight: 600;           /* synthetic — the face ships one weight */
  font-size: 32px;
  letter-spacing: .005em;
  line-height: .95;
  color: var(--ink);
  margin: 0;
}

.sidebar__tagline {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .14em;
  line-height: 1.4;
  color: var(--ink-b3);
  margin: 6px 0 0;
}

.sidebar__nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;              /* 50px pill + 10px gap = 60px pitch */
  padding: 0 26px;
}

.sidebar__link {
  display: flex;
  align-items: center;
  width: 150px;
  height: 50px;
  padding: 0 8px;
  border-radius: 12px;
  font-family: var(--font-nav);
  font-weight: 700;
  font-size: 26px;
  line-height: 34px;
  /* No pill: the current page is marked by ink alone. The other pages sit in a
     soft warm taupe (3.2:1 on the sidebar, fine for 26px bold), hover darkens
     them, and the current page takes the full terracotta accent. */
  color: var(--nav-ink, #9c8b7d);
  transition: color .15s ease;
}
.sidebar__link:hover { color: var(--nav-ink-hover, #5c554a); }
.sidebar__link.is-active { color: var(--nav-ink-active, var(--accent)); }

/* --- THIS TERM (build B §3.4) ----------------------------------------------
   Sits immediately after the nav. B reads doneCr/totalCr/inProgCr/pct from its
   coursemap API; A has no backend, so js/sidebar.js paints these from the
   `term` bucket in js/store.js (seeded to match Home and Profile).           */
.sidebar__term { margin-top: 26px; padding: 0 34px; }

.term__label {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .14em;
  line-height: 1.4;
  color: var(--dim);
  margin: 0 0 10px;
}
.term__line {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-2);
  margin: 0;
}
.term__pct {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 12px 0 0;
  flex-wrap: nowrap;
}
.term__pct-num {
  font-family: var(--font-initials);
  font-size: 19px;
  line-height: 1;
  flex: none;
}
.term__pct-cap { font-size: 11px; color: var(--ink-b3); white-space: nowrap; }

.term__bar {
  height: 6px;
  border-radius: 3px;
  background: var(--border-soft);
  margin-top: 8px;
  overflow: hidden;
  display: flex;
  gap: 1px;
}
.term__bar-done { background: var(--green); }
.term__bar-prog { background: var(--accent-b); opacity: .45; }

/* --- profile circle (build B §6) -------------------------------------------
   B ships no avatar image: the circle is the student's own upload or an
   initials fallback. This is the fallback treatment — #F1E3D8 on a #DFC2AC
   hairline, initials in Newsreader at #7E3F22. B registers 32px/14px and
   74px/26px; A's slots are bigger, so the 26/74 = .351 ratio is carried over
   (89px → 31px, 128px → 45px).                                              */
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent-wash);
  border: 1px solid var(--accent-wash-line);
  color: var(--accent-deep);
  font-family: var(--font-newsreader);
  font-weight: 400;
  line-height: 1;
  overflow: hidden;
  user-select: none;
}
/* Doubled class so it beats the page stylesheets that load after base.css
   (home.css / profile.css / career.css each set their own size + fill). */
.avatar.avatar--lg {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 128px; height: 128px; flex: 0 0 128px;
  font-size: 45px;
  background: var(--accent-wash);
  border: 1px solid var(--accent-wash-line);
  border-radius: 50%;
  color: var(--accent-deep);
}

.sidebar__foot { margin-top: auto; padding: 0 0 60px 50px; }

/* --- short windows ----------------------------------------------------------
   The rail's own content is 819px tall at its drawn spacing (32 top pad + 122
   brand + 350 nav + 26 + 103 THIS TERM + 89 avatar + 37 SIGN OUT + 60 bottom
   pad), so anything shorter than an 819px window clipped the avatar and the
   sign-out control off the bottom — a 1280x800 laptop lost 19px of it and a
   1280x700 window lost 119px. Nothing here changes above 845px; below that the
   rail tightens the four spacing values that carry the most slack, and below
   760px the nav pill shrinks from 50px to 42px as well (the 26px label still
   clears its 34px line box). That brings the content to 666px, so the whole
   rail fits a 700px window with room to spare. `overflow-y: auto` is only the
   last-resort net below that. */
@media (max-height: 845px) {
  .sidebar { padding-top: 24px; }
  .sidebar__brand { padding-bottom: 16px; }
  .sidebar__nav { gap: 6px; }
  .sidebar__term { margin-top: 18px; }
  .sidebar__foot { padding-bottom: 42px; }
}

@media (max-height: 760px) {
  .sidebar { padding-top: 16px; }
  .sidebar__brand { padding-bottom: 10px; }
  .sidebar__nav { gap: 5px; }
  .sidebar__link { height: 42px; }
  .sidebar__term { margin-top: 12px; }
  .sidebar__foot { padding-bottom: 24px; }
}

.sidebar { overflow-y: auto; scrollbar-width: thin; }
/* 89px was A's Figma slot, but that is 41% of the 217px rail and dwarfs the
   40px brand mark above it. 56px sits between build B's own 32px sidebar
   avatar and A's slot: clearly a secondary control, 1.4x the mark, and it
   gives 33px back to the vertical budget on short windows. Initials keep the
   .351 cap-height ratio the other sizes use. */
.sidebar__avatar {
  width: 56px; height: 56px; flex: 0 0 56px;
  font-size: 20px;
  box-shadow: none;
}
.sidebar__avatar:hover { box-shadow: 0 0 0 3px var(--accent-line); }
/* The avatar is the link to the student's own profile, so it carries the
   current-page state on profile.html (no nav item points there). */
.sidebar__avatar[aria-current] { box-shadow: 0 0 0 2px var(--accent); }

/* One canonical content gutter, identical on every document page.
   Each Figma frame had its own content origin (39/37/38/20px from the sidebar,
   60/29/21/40px from the right edge), so every page used to sit at a different
   distance from the rail. 40px is the single value now: it is the median of the
   drawn left insets, it is already the site's spacing step (8 x 5), and making
   left and right equal frames the content symmetrically in the content area
   however wide it gets. No page overrides this — the only exceptions are the
   three full-bleed boards (plan / goals / planner), which set `padding: 0`
   because they are whiteboards that fill the viewport. */
.main { flex: 1 1 auto; min-width: 0; padding: 20px 40px 40px; }

/* The audit found `.visa { display: flex }` silently beating the UA sheet's
   `[hidden] { display: none }`, so a "Don't show again" button wrote its flag
   to localStorage and was then ignored forever. Any author `display` on an
   element that also gets toggled with [hidden] reintroduces that bug, so the
   rule is settled once, globally. */
[hidden] { display: none !important; }

/* --- primitives ------------------------------------------------------------ */

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 20px;
}
.panel--flat { border-color: transparent; box-shadow: var(--sh-2); }

.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--ink-3);
}

.hand { font-family: var(--font-hand); font-weight: 400; }
.serif { font-family: var(--font-serif); font-weight: 600; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 44px; padding: 0 20px;
  border-radius: 10px;
  background: var(--accent); color: #fff;
  font-size: 18px; font-weight: 500;
  transition: filter .15s ease, transform .05s ease;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: translateY(1px); }
.btn--sm { height: 32px; padding: 0 14px; font-size: 13.5px; border-radius: 10px; }
.btn--ghost {
  background: transparent; color: var(--ink-2);
  border: 1px solid var(--border);
}
.btn--ghost:hover { background: var(--panel); filter: none; }

.link { color: var(--accent); font-weight: 500; }
.link:hover { text-decoration: underline; }

.tag {
  display: inline-flex; align-items: center; height: 18px; padding: 0 10px;
  border-radius: 9px;
  font-size: 9px; font-weight: 600; letter-spacing: .45px;
}
.tag--internship { background: var(--accent-tint); color: var(--accent); }
.tag--research   { background: var(--green-tint);  color: var(--green); }
.tag--oncampus   { background: var(--amber-tint);  color: var(--amber); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--panel);
  transition: background .15s ease;
}
.icon-btn:hover { background: var(--accent-tint); }
.icon-btn img { width: 20px; height: 20px; }

.divider { height: 1px; background: var(--border); border: 0; margin: 0; }

/* checkbox — square, hand-drawn feel */
.check {
  appearance: none;
  width: 15px; height: 15px; flex: 0 0 15px;
  border: 1.5px solid var(--accent);
  border-radius: 3px;
  background: transparent;
  cursor: pointer;
  position: relative;
  transition: background .12s ease;
}
.check:checked { background: var(--accent); }
.check:checked::after {
  content: '';
  position: absolute; left: 4px; top: 1px;
  width: 4px; height: 8px;
  border: solid #fff; border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg);
}

/* scrollbars inside panels */
.scroll { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) var(--scroll-track); }
.scroll::-webkit-scrollbar { width: 6px; }
.scroll::-webkit-scrollbar-track { background: var(--scroll-track); border-radius: 3px; }
.scroll::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 3px; }

/* Printing. The only page anyone prints is the resume, whose Export button calls
   window.print() on the live page — so without this the exported PDF carries the
   sidebar, the mascot and the floating toolbar down the side of the document a
   student is sending to an employer. Screen chrome is not part of the paper. */
@media print {
  .sidebar,
  .mascot,
  .wb-chrome,
  .fp-banner { display: none !important; }

  .app  { display: block; }
  .main { padding: 0; }

  body {
    background: #fff;
    color: #000;
  }
}

/* --- mascot ---------------------------------------------------------------- */

/* The corner pigeon scales with the screen instead of sitting at a fixed pixel
   width. A fixed 360px was 53% of the height on a 1280x720 laptop and 27% on a
   2560x1440 monitor. Both sizes are pinned to the proportions approved at
   1440x900 (42% and 29% of the viewport height), capped by width so a tall or
   narrow screen cannot blow the bird up, and clamped at both ends.
   The sprite frame is 280x297, so height = width x 1.061. */
:root {
  --mascot-lg: clamp(180px, min(39.6vh, 25vw), 480px);   /* profile, resume, visa */
  --mascot-sm: clamp(150px, min(27.3vh, 17vw), 340px);   /* home, goals */
}

.mascot {
  position: fixed;
  right: 0; bottom: 0;
  width: var(--mascot-lg);
  pointer-events: none;
  /* Over everything on the page, under the modal backdrop at 40 — a dialog
     covering the bird is right, a card covering it is not. */
  z-index: 30;
}
/* The corner mascot is the same 11 x 11 sheet the quiz pigeon uses. Only the
   box is set here — js/pigeon.js writes background-size and background-position
   from the element's own measured size, so the two pigeons can differ in scale
   and still step in lockstep. The aspect ratio is one native frame, 280 x 297. */
#pigeon-stage {
  aspect-ratio: 280 / 297;
  /* The box around it ignores the pointer; the bird itself can be picked up
     and dragged out of the way (js/pigeon.js). */
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  user-select: none;
  background-image: url('../assets/b/pigeon-stage.webp');
  background-repeat: no-repeat;
}
/* Width is left to whichever mascot box holds it: the corner one fills its
   260px container, the whiteboard's is pinned to 177px by css/plan.css. Setting
   it on the id here would outrank both. */
.mascot #pigeon-stage { width: 100%; position: relative; z-index: 2; }

/* Its moon (js/pigeon.js adds it under the bird). Same proportions as the Goals
   board's planet — 95.9% of the bird's width, tucked 13% up under its feet and
   4.1% to the left — and drawn behind the bird so the feet stand on it. */
.mascot .mascot__moon {
  display: block;
  position: relative;
  z-index: 1;
  width: 95.9%;
  height: auto;
  margin: -13% 0 0 -4.1%;
  /* Only the top of the moon needs to show: this pulls the box's bottom edge up
     by about a third of the bird's width, so a box pinned to the bottom of the screen
     lets the rest of the moon hang below it. The bird stays where it was. */
  margin-bottom: -35%;
  pointer-events: none;
  user-select: none;
}

/* Safari before 15 has no aspect-ratio, which left the bird 0px tall — so it
   neither showed nor animated. The padding box gives it the same shape. */
@supports not (aspect-ratio: 1 / 1) {
  .mascot #pigeon-stage { height: 0; padding-bottom: 106.07%; }   /* % of the box, which is the bird's own width */
}
.is-dragging #pigeon-stage { cursor: grabbing; }
#pigeon-stage:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 12px; }
/* --- the pigeon's speech bubble (build B's #pigeon-dock bubble) -------------
   Built by js/pigeon.js. B's literal colours are the defaults; the NYU theme
   overrides the --pg-* tokens below. It opens to the bird's left with B's tail
   pointing at it, and flips to the right when the bird is dragged too far left. */
:root {
  --pg-paper: #faf8f1; --pg-line: #363636; --pg-head: #8c4535; --pg-from: #9a8f7d;
  --pg-text: #363636; --pg-cheer: #a2593a; --pg-dash: #e0d8c6; --pg-act: #8c4535;
  --pg-act-ink: #fdfbf6; --pg-done: #5a7355; --pg-box: #6b6055;
}
/* The outline is two SVGs drawn by js/pigeon.js: a wobbly, pen-drawn body that
   stretches to the text (its stroke does not stretch with it), and a fixed-size
   tail whose tip js/pigeon.js parks on the bird's beak. Neither the right/bottom
   nor left/bottom offsets live here; they are measured from the sprite. */
.pg-bubble {
  position: absolute;
  width: max-content;
  max-width: min(300px, calc(100vw - 130px));
  padding: 19px 30px 19px 20px;
  pointer-events: auto;
  cursor: auto;
  text-align: left;
  z-index: 3;
}
.pg-bubble[hidden] { display: none !important; }
.pg-bubble__x {
  position: absolute; top: 8px; right: 10px;
  padding: 2px 4px; font-size: 12px; line-height: 1; color: var(--pg-from);
}
.pg-bubble__x:hover { color: var(--pg-line); }
.pg-bubble__head { font-family: var(--font-nav); font-size: 18px; line-height: 1.25; color: var(--pg-head); }
.pg-bubble__from { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 8px; letter-spacing: .12em; color: var(--pg-from); margin-top: 2px; }
.pg-bubble__msg { font-family: var(--font-nav); font-size: 15px; line-height: 1.3; color: var(--pg-text); margin-top: 5px; text-wrap: pretty; }
.pg-item { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.pg-item__box {
  flex: none; width: 15px; height: 15px; border-radius: 4px;
  border: 1.5px solid var(--pg-box); background: #fff; color: var(--pg-box);
  font-size: 10px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0;
}
.pg-item__box.is-done { border-color: var(--pg-done); background: var(--pg-done); color: #fdfbf6; }
.pg-item__box.is-go { border-radius: 50%; }
.pg-item__text {
  flex: 1; font-family: var(--font-nav); font-size: 15px; line-height: 1.25; text-align: left;
  color: var(--pg-text); cursor: pointer; padding: 0;
}
.pg-item__text.is-done { color: var(--pg-from); text-decoration: line-through; }
.pg-item__chip {
  flex: none; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 7.5px; letter-spacing: .08em;
  padding: 2px 7px; border-radius: 8px; color: #fdfbf6;
}
.pg-bubble__act {
  display: inline-block; background: var(--pg-act); color: var(--pg-act-ink); border-radius: 14px;
  padding: 7px 14px; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .04em;
  margin-top: 10px; margin-right: 8px; text-decoration: none;
}
.pg-bubble__cheer {
  font-family: var(--font-nav); font-size: 13.5px; line-height: 1.35; color: var(--pg-cheer);
  margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--pg-dash);
}
.pg-bubble__shape {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
  z-index: -1;
  filter: drop-shadow(2px 3px 0 rgba(54, 54, 54, .22));
  pointer-events: none;
}
.pg-bubble__tail {
  position: absolute;
  left: calc(100% - 26px); top: calc(100% - 8px);
  width: 34px; height: 36px;
  overflow: visible;
  z-index: -1;
  pointer-events: none;
}
.pg-bubble__fill { fill: var(--pg-paper); }
.pg-bubble__ink  { fill: none; stroke: var(--pg-line); stroke-width: 2.2px; stroke-linecap: round; stroke-linejoin: round; }
.pg-bubble__ink--2 { stroke-width: 1px; opacity: .55; }
/* Dragged to the left edge: the bubble opens on the other side, tail mirrored. */
.pg-flip .pg-bubble { padding: 19px 20px 19px 30px; }
.pg-flip .pg-bubble__x { right: auto; left: 7px; }
/* mirrored: the tail leaves the bottom-left corner instead */
.pg-flip .pg-bubble__tail { left: -8px; transform: scaleX(-1); }

/* Pages without their own mascot markup (Career, Alumni) get the small bird. */
.mascot--injected { width: var(--mascot-sm); }

/* Planner: only the head pokes in from the right edge, low on the screen. The
   bird leans in from off-screen; everything below the helmet stays past the
   edge. Dragging slides it up and down that edge. */
/* Tucked away: only the head pokes in from the right edge. Home, Goals and the
   Planner each size and place their own mascot, and those rules are more
   specific than this one, so the three geometry values that define the tuck are
   forced. The vertical position is left to whatever holds it (a page rule, or
   an inline top from dragging it up the edge). */
.mascot--peek {
  --peek: clamp(120px, min(24vh, 15vw), 260px);
  width: var(--peek) !important;
  left: auto !important;
  right: calc(var(--peek) * -.52) !important;
}
.mascot--peek #pigeon-stage {
  width: 100% !important;
  transform: rotate(-38deg);
  transform-origin: 50% 60%;
}
/* the Goals bird stands on a planet; tucked at the edge it leaves it behind */
.mascot--peek .planet { display: none; }

/* the button that tucks it away sits at the foot of the bubble */
.pg-bubble__tuck {
  display: block;
  margin-top: 10px;
  font-family: var(--font-nav);
  font-size: 13px;
  color: var(--pg-from);
}
.pg-bubble__tuck:hover { color: var(--pg-head); }

/* --- modal ----------------------------------------------------------------- */

.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(27, 25, 22, .38);
  display: none;
  align-items: center; justify-content: center;
  padding: 24px;
  z-index: 40;
}
.modal-backdrop.is-open { display: flex; }

.modal {
  position: relative;
  background: var(--panel-alt);
  border-radius: 22px;
  box-shadow: var(--sh-5);
  max-width: 100%;
  max-height: 100%;
  overflow: auto;
}
.modal__close {
  position: absolute; top: 18px; right: 18px;
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1; color: var(--ink-3);
}
.modal__close:hover { background: var(--border-soft); color: var(--ink); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}


/* ===========================================================================
   § NYU THEME — :root[data-brand="nyu"], switched from the sidebar.

   From NYU's own brand guidelines:
     · NYU Violet #57068C is the primary and appears in every version of the
       palette; the violet scale runs #330662, #702B9D, #7B5AA6, #AB82C5 and
       #EEE6F3 (10% violet).
     · Neutrals are cool greys: #000, #404040, #6D6D6D, #B8B8B8, #D6D6D6,
       #F2F2F2, #FFF. Accents: teal #00B8A2 / deep teal #00837C, blue #59B2D1 /
       deep blue #4E7AA1, magenta #FB0F78 / deep magenta #E00E78, yellow #F4EC51.
     · The typeface is NYU Perstare, which is licensed to NYU and not public.
       The guidelines name Montserrat as its fallback, and Frank Ruhl Libre as a
       serif to pair with it: headings in one, body in the other, never an
       all-serif page. Here that is Frank Ruhl Libre headings, Montserrat for
       everything else.

   Where the palette has no step light or dark enough for a job (a tint behind
   text, or a grey legible at 8px), the value is a tint or shade of a palette
   colour rather than a new hue. No NYU logo is used: this is a colour and type
   theme, not a claim of affiliation.
   =========================================================================== */
:root[data-brand="nyu"] {
  --bg: #f2f2f2; --panel: #ffffff; --panel-alt: #ffffff; --sidebar: #ffffff; --sunken: #f2f2f2;
  --border: #d6d6d6; --border-soft: #e6e6e6; --placeholder: #d6d6d6;
  --ink: #000000; --ink-2: #404040; --ink-3: #6d6d6d; --ink-4: #767676;
  --accent: #57068c; --accent-tint: #eee6f3; --accent-soft: #f6f1f9; --accent-line: #ab82c5;
  --green: #00837c; --green-tint: #e0f2f0; --amber: #4e7aa1; --amber-tint: #e3ecf4; --star: #f4ec51;
  --scroll-track: #e6e6e6; --scroll-thumb: #b8b8b8;
  --c-cs: #eee6f3; --c-math: #e0f2f0; --c-phys: #fbf8d9; --c-engl: #fde7f1; --c-psy: #e3ecf4;

  --rule: #d6d6d6; --ink-b3: #6d6d6d; --dim: #8a8a8a; --accent-b: #57068c;
  --accent-deep: #330662; --accent-wash: #eee6f3; --accent-wash-line: #ab82c5;
  --ink-warm: #404040; --visa-bg: #eee6f3; --visa-line: #ab82c5;
  --dot-alert: #e00e78; --dot-warn: #4e7aa1; --danger: #e00e78;
  --placeholder-ink: #6d6d6d; --divider-warm: #e6e6e6; --chip-bg: #f2f2f2;
  --badge: #6d6d6d; --title-ink: #000000;
  --sch-math: #e0f2f0; --sch-phys: #fbf8d9; --sch-engl: #fde7f1; --sch-psy: #e3ecf4;
  --sch-engl-ink: #b00b5e; --sch-phys-ink: #5c5700; --sch-psy-ink: #355a7a;
  --fp-habits-bg: #fbf8d9; --fp-habits-line: #e8e08a; --fp-wins-bg: #f7f7f7; --fp-wins-line: #e6e6e6;
  --fp-faint: #b8b8b8; --fp-gold-ink: #5c5700; --fp-gold: #7a7200; --fp-cream: #ffffff;
  --fp-cal-dark: #404040; --fp-sage-line: #cce6e4; --fp-off: #d6d6d6;
  --q-line: #d9c7e6; --q-box: #b8b8b8; --q-cream: #ffffff; --q-x: #6d6d6d; --q-dot: #d6d6d6;
  --q-ink2: #404040; --q-ink: #000000; --q-edge: #404040; --q-radio: #b8b8b8;
  --q-dash: #b8b8b8; --q-field: #d6d6d6;

  /* login.css declares its own tokens */
  --b-accent: #57068c; --b-rule: #d6d6d6; --b-ink3: #6d6d6d; --b-dim: #8a8a8a;
  --b-err-ink: #b00b5e; --b-err-bg: #fde7f1; --b-err-line: #f39ac4;
  --b-pend-bg: #f6f1f9; --b-pend-ln: #ab82c5; --b-pend-ink: #330662;

  --font-hand:       'Frank Ruhl Libre', Georgia, serif;
  --font-serif:      'Frank Ruhl Libre', Georgia, serif;
  --font-newsreader: 'Frank Ruhl Libre', Georgia, serif;
  --font-body:       'Montserrat', Verdana, sans-serif;
  --font-mono:       'Montserrat', Verdana, sans-serif;
  --font-initials:   'Frank Ruhl Libre', Georgia, serif;
}

/* The Goals whiteboard declares its own palette on the page body. */
:root[data-brand="nyu"] .page-plan,
:root[data-brand="nyu"] .page-goals {
  --pl-paper: #ffffff; --pl-stone: #eeeeee; --pl-sage: #e0f2f0; --pl-wheat: #fbf8d9;
  --pl-clay: #eee6f3; --pl-shade: #d6d6d6; --pl-rule: #d6d6d6; --pl-cast: rgba(51, 6, 98, .14);
  --fp-rule: #d6d6d6; --fp-hair: #eeeeee; --fp-ink3: #6d6d6d; --fp-dim: #8a8a8a;
  --fp-accent: #57068c; --fp-deep: #330662; --fp-tint: #eee6f3; --fp-tint-line: #ab82c5;
  --fp-star: #d4c11a; --fp-star-lit: #f4ec51; --fp-dot: #cfcfcf;
}
:root[data-brand="nyu"] .fp-letter__err { --fp-err: #b00b5e; }
:root[data-brand="nyu"] {
  --pg-paper: #ffffff; --pg-line: #57068c; --pg-head: #57068c; --pg-from: #6d6d6d;
  --pg-text: #222222; --pg-cheer: #57068c; --pg-dash: #d6d6d6; --pg-act: #57068c;
  --pg-act-ink: #ffffff; --pg-done: #00756f; --pg-box: #6d6d6d;
}

/* The nav buttons keep the default handwritten face (--font-nav is not
   overridden above), so they keep its size too. Only the wordmark, which does
   switch to the serif, is brought back to scale. */
:root[data-brand="nyu"] .sidebar__title { font-size: 30px; font-weight: 700; }

/* --- the theme toggle (built by js/sidebar.js under THIS TERM) ------------ */
.sidebar__theme { margin-top: 18px; padding: 0 34px; }
.theme-toggle {
  display: flex;
  gap: 3px;
  margin-top: 6px;
  padding: 3px;
  background: var(--sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.theme-toggle button {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 5px 8px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  transition: background .15s ease, color .15s ease;
}
.theme-toggle button:hover { color: var(--ink); }
.theme-toggle button[aria-pressed="true"] { background: var(--panel); color: var(--accent); box-shadow: var(--sh-1); }
.theme-toggle__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.theme-toggle__dot--fp  { background: #8c4535; }
.theme-toggle__dot--nyu { background: #57068c; }

/* ===========================================================================
   § NYU — SOLID VIOLET. NYU's identity is the violet itself, used as a solid
   block with white type, not a 10% tint behind violet text. So in this theme:
   the sidebar is a solid NYU Violet rail; anything selected or labelled is
   solid violet with white text; large highlighted panels drop the lavender
   wash for a white card with a solid violet rule; headings take the violet.
   White on #57068C is 10.3:1. No transparency anywhere on the violet.
   =========================================================================== */

/* the rail */
:root[data-brand="nyu"] .sidebar { background: #57068c; border-right-color: #330662; }
:root[data-brand="nyu"] .sidebar__title,
:root[data-brand="nyu"] .term__line,
:root[data-brand="nyu"] .term__pct-num { color: #ffffff; }
:root[data-brand="nyu"] .sidebar__tagline,
:root[data-brand="nyu"] .term__label,
:root[data-brand="nyu"] .term__pct-cap { color: #d9c7e6; }
/* NYU: other pages in light violet (5.6:1 on the violet sidebar), the current
   page pure white. */
:root[data-brand="nyu"] { --nav-ink: #c9a8e0; --nav-ink-hover: #e8dbf2; --nav-ink-active: #ffffff; }
:root[data-brand="nyu"] .term__bar { background: #330662; }
:root[data-brand="nyu"] .term__bar-done { background: #ffffff; }
:root[data-brand="nyu"] .term__bar-prog { background: #ab82c5; opacity: 1; }
:root[data-brand="nyu"] .sidebar .avatar { background: #ffffff; border-color: #ffffff; color: #57068c; }
:root[data-brand="nyu"] .sidebar__avatar:hover { box-shadow: 0 0 0 3px #ab82c5; }
:root[data-brand="nyu"] .sidebar :is(.signout, .sidebar__signout) { color: #ffffff; border-color: #ab82c5; background: transparent; }
:root[data-brand="nyu"] .theme-toggle { background: #330662; border-color: #330662; }
:root[data-brand="nyu"] .theme-toggle button { color: #d9c7e6; }
:root[data-brand="nyu"] .theme-toggle button:hover { color: #ffffff; }
:root[data-brand="nyu"] .theme-toggle button[aria-pressed="true"] { background: #ffffff; color: #57068c; }

/* selected / labelled: solid violet, white type */
:root[data-brand="nyu"] :is(
  .tag--internship, .appl__tag--applied, .al-state--sent, .rz-card__badge, .chip,
  .al-chip[aria-pressed="true"], .al-bookmark[aria-pressed="true"], .al-avatar,
  .planner-toggle button.is-on, .pl-tools button.is-on, .gb-tools button.is-on,
  .fp-goal__rank, .vs-remind__when, .wb-clear__btn.is-armed,
  .startup[data-startup="nimbus"] .startup__logo, .startups__wide-logo[data-tone="peach"]
) { background: #57068c; color: #ffffff; border-color: #57068c; }
:root[data-brand="nyu"] .pl-tools button.is-on img,
:root[data-brand="nyu"] .gb-tools button.is-on img { filter: brightness(0) invert(1); }

/* the CS course is the one violet subject in the schedule */
:root[data-brand="nyu"] :is(.course--cs, .block--cs),
:root[data-brand="nyu"] .course--cs * { background-color: #57068c; color: #ffffff; }
:root[data-brand="nyu"] .course--cs * { background-color: transparent; }

/* large highlighted panels: white card, solid violet rule, no lavender wash */
:root[data-brand="nyu"] :is(.visa, .visa-panel, .vs-card--accent, .job-detail__visa) {
  background: #ffffff;
  border: 1px solid #d6d6d6;
  border-top: 5px solid #57068c;
}
:root[data-brand="nyu"] .vs-lesson.is-flagged { background: #ffffff; box-shadow: inset 4px 0 0 #57068c; }
:root[data-brand="nyu"] .al-card__shared { background: #ffffff; color: #57068c; box-shadow: inset 3px 0 0 #57068c; border-radius: 3px; }
:root[data-brand="nyu"] .avatar.avatar--lg { background: #57068c; border-color: #57068c; color: #ffffff; }

/* headings carry the violet */
:root[data-brand="nyu"] :is(.semester__hello, .pipeline__title, .goals-panel__title, .visa-panel__title,
  .visa__title, .al-head__title, .al-rail__title, .al-detail__name, .profile-card__name) { color: #57068c; }

/* --- NYU: legibility on the new solid surfaces --------------------------- */
/* a count inside a solid violet chip */
:root[data-brand="nyu"] .al-chip[aria-pressed="true"] .al-chip__count { color: #d9c7e6; }

/* The visa page keeps its own ink ramp on the page body. */
:root[data-brand="nyu"] .page-visa {
  --vs-ink: #404040; --vs-ink-2: #6d6d6d; --vs-track: #e6e6e6; --vs-box: #b8b8b8; --vs-quote: #6d6d6d;
}

/* NYU's teal and blue at small sizes land just under 4.5:1 on the grey ground;
   a shade darker in the same families clears it (about 5:1). */
:root[data-brand="nyu"] { --green: #00756f; --amber: #3e6a90; --dim: #6d6d6d; }
:root[data-brand="nyu"] .page-plan,
:root[data-brand="nyu"] .page-goals { --fp-dim: #6d6d6d; }
:root[data-brand="nyu"] .week__hour { color: #6d6d6d; }

/* Saved-list titles are pills, so they get the solid treatment too. */
:root[data-brand="nyu"] .saved-rail__title { background: #57068c; color: #ffffff; border-color: #57068c; }
:root[data-brand="nyu"] .saved-rail__item[data-tone="sage"] .saved-rail__title { background: #00756f; border-color: #00756f; }

/* --- NYU: the last pale and faint spots ---------------------------------- */
/* The Goals "this week" CS chip is painted inline from var(--c-cs); match the
   inline value so it joins the schedule's solid violet CS blocks. */
:root[data-brand="nyu"] .fp-week__chip[style*="--c-cs"] { background: #57068c !important; color: #ffffff; }

/* The schedule's day and hour labels and the scrollbar share one grey; at
   #B8B8B8 the labels were 1.8:1. #6D6D6D is NYU's mid grey and clears 4.5:1. */
:root[data-brand="nyu"] { --scroll-thumb: #6d6d6d; }

/* footer hints on the whiteboard, and a count on a grey pill */
:root[data-brand="nyu"] .page-plan,
:root[data-brand="nyu"] .page-goals { --fp-faint: #767676; }
:root[data-brand="nyu"] .saved-rail__count { color: #404040; }

/* the wins marker takes the violet: NYU's yellow on white is only 1.7:1 */
:root[data-brand="nyu"] .fp-wins__star { color: #57068c; }

/* whiteboard banner star count, and the footer hint on its near-white cards */
:root[data-brand="nyu"] .fp-banner__stars { color: #57068c; }
:root[data-brand="nyu"] .page-plan,
:root[data-brand="nyu"] .page-goals { --fp-faint: #6d6d6d; }


/* ===========================================================================
   § PHONES + SMALL TABLETS (≤ 900px)
   The 217px rail would leave a phone ~160px of page, so below 900px it becomes
   a 56px top bar: brand on the left, a menu button on the right (built by
   js/sidebar.js). The rest of the rail opens as a full-screen menu under the
   bar. Pages get a 16px gutter and never scroll sideways. Page stylesheets add
   their own rules for this width below their desktop ones.
   =========================================================================== */

.sidebar__menu-btn { display: none; }

@media (max-width: 900px) {
  html, body { overflow-x: hidden; }

  .app { display: block; min-height: 100vh; }

  .sidebar {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 35;            /* over the pigeon (30), under modals (40) */
    width: auto;
    height: 56px;
    padding: 0 8px 0 16px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    align-content: start;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    overflow: hidden;
  }
  .sidebar__brand { display: flex; align-items: center; gap: 9px; padding: 0; height: 56px; }
  .sidebar__mark { width: 28px; height: 26px; margin: 0; }
  .sidebar__title { font-size: 24px; line-height: 1; }
  :root[data-brand="nyu"] .sidebar__title { font-size: 22px; }
  .sidebar__tagline { display: none; }

  .sidebar__menu-btn {
    display: inline-flex; flex-direction: column; justify-content: center; align-items: center; gap: 5px;
    width: 44px; height: 44px;
    border-radius: 10px;
  }
  .sidebar__menu-btn span {
    display: block; width: 22px; height: 2px; border-radius: 2px;
    background: var(--ink);
    transition: transform .2s ease, opacity .2s ease;
  }
  :root[data-brand="nyu"] .sidebar__menu-btn span { background: #ffffff; }
  .sidebar.is-open .sidebar__menu-btn span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .sidebar.is-open .sidebar__menu-btn span:nth-child(2) { opacity: 0; }
  .sidebar.is-open .sidebar__menu-btn span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* everything under the brand row lives in the menu */
  .sidebar > :where(:not(.sidebar__brand):not(.sidebar__menu-btn)) { display: none; grid-column: 1 / -1; }
  .sidebar.is-open {
    z-index: 70;
    height: 100vh; height: 100dvh;
    overflow-y: auto;
    padding-bottom: 32px;
  }
  .sidebar.is-open > :where(:not(.sidebar__brand):not(.sidebar__menu-btn)) { display: block; }
  .sidebar.is-open .sidebar__nav { display: flex; gap: 4px; padding: 16px 8px 0; }
  .sidebar.is-open .sidebar__link { width: 100%; height: 48px; padding: 0 8px; font-size: 28px; }
  .sidebar.is-open .sidebar__term,
  .sidebar.is-open .sidebar__theme { padding: 0 16px; margin-top: 22px; }
  .sidebar.is-open .theme-toggle { max-width: 260px; }
  .sidebar.is-open .sidebar__foot {
    display: flex; align-items: center; gap: 16px;
    margin-top: 26px; padding: 0 16px;
  }
  .sidebar.is-open .sidebar__foot .signout { margin: 0; }
  body.nav-open { overflow: hidden; }

  .main { padding: 72px 16px 40px; min-width: 0; }

  /* the corner pigeon: small enough to live beside content on a phone */
  :root {
    --mascot-lg: clamp(84px, 26vw, 130px);
    --mascot-sm: clamp(78px, 23vw, 118px);
  }

  /* modals take the screen instead of floating in a 24px frame */
  .modal-backdrop { padding: 12px; }
}
