/* Direction B — restored and responsive. Palette and type from the mockup. */
:root{
  --ground:#f4f2ed; --ink:#23211d; --dim:#55504a; --faint:#6b655c;
  --line:#e2ddd3; --panel:#fff; --dark:#1c1a17; --red:#9a2313; --gold:#e8b431;
  --maroon:#660000;
}
*{box-sizing:border-box}
body{margin:0;background:var(--ground);color:var(--ink);
     font-family:'Source Sans 3','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:16px;line-height:1.55}
a{color:var(--red);text-decoration:none}
a:hover{color:#c8102e;text-decoration:underline}
.serif{font-family:'Source Serif 4',Georgia,'Times New Roman',serif}
.wrap{max-width:940px;margin:0 auto;padding:0 20px}

/* header */
/* Berkeley High's own maroon, sampled from the school's logo: the seal's
   gold ring is the brightest thing in the bar against it. */
.masthead{background:var(--maroon);color:var(--ground);position:relative}
.masthead .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px;
                padding-top:14px;padding-bottom:14px;flex-wrap:wrap}
/* The yearbook header, James 2026-09-19 (mock-up B of five): hundreds of tiny
   portraits, faded like old yearbook paper, with the words in maroon. The
   picture is one prebuilt JPEG with the fade baked in
   (tools/build_header_collage.py); base.html points at it, so the maroon above
   still shows if it ever fails to load. */
.masthead.yb{background:var(--ground) repeat-x center/auto 100%;color:var(--maroon)}
.masthead.yb{--seal:80px;--pt:24px}
.masthead.yb .wrap{padding-top:var(--pt);padding-bottom:12px;row-gap:14px}
.masthead.yb .brand img{width:var(--seal)}
.masthead.yb .nav{line-height:30px}
/* Sticky menu on a desktop (James, 2026-09-19): the whole header sticks, but
   pulled up by everything above the menu row - the top padding, the seal and
   the gap - less 8px of air, so once you scroll only the menu row stays
   (8 + 30 + 12 = 50px, which is where the reunion banner pins below it). */
@media (min-width:1101px){
  .masthead.yb{position:sticky;z-index:57;top:calc(-1 * (var(--pt) + var(--seal) + 14px - 8px))}
}
.masthead.yb .brand span{font-size:29px}
.masthead.yb .brand span b{font-weight:inherit}
.masthead.yb .brand span i{font-style:normal}
/* One line (James, 2026-09-19): eleven items at 18px need about 1000px, so the
   header gets a wider column than the page below it, and on a smaller laptop
   the text steps down a little rather than wrapping. */
.masthead.yb .wrap{max-width:1140px}
/* The menu has a line of its own under the seal and spreads its items across
   it: the gaps are whatever room is left once every word fits, never less than
   12px. A gap computed from the window width kept growing after the header
   stopped and pushed Sign out off the edge (James, 2026-09-27). */
.masthead.yb .nav{font-size:clamp(15px,1.35vw,18px);gap:12px;flex-wrap:nowrap;
                  white-space:nowrap;flex:1 0 100%;justify-content:space-between}
.masthead.yb .nav a{color:var(--maroon)}
/* Level with the name on the left (James, 2026-09-19), not centred on the bar:
   the top padding plus half the seal. */
.masthead.yb .fifty{top:calc(var(--pt) + var(--seal) / 2);font-size:58px}
/* The page you are on: red on maroon did not show, so extra-bold with a thick
   underline (James, 2026-09-19: "Can the selected menu be bolded?"). */
.masthead.yb .nav a.on{color:var(--maroon);font-weight:800;box-shadow:inset 0 -3px 0 var(--red)}
.masthead.yb .nav a.adm{color:#9a6a00}
/* Gold, the theme colour (James, 2026-09-19), with a thin dark edge so it
   still reads on the pale faces. */
.masthead.yb .fifty{color:var(--gold);
                    text-shadow:0 1px 0 #5a0000,0 -1px 0 #5a0000,1px 0 0 #5a0000,-1px 0 0 #5a0000,
                                0 2px 6px rgba(60,0,0,.35)}
.brand{display:flex;align-items:center;gap:13px}
.brand img{width:38px;height:auto}
.brand span{font-family:'Source Serif 4',Georgia,serif;font-size:19px;font-weight:700}
.nav{display:flex;gap:22px;font-size:15px;font-weight:600;flex-wrap:wrap}
/* The anniversary, in the hand the mark uses. Sits last in the bar and
   steps aside on a phone, where the nav already fills the width. */
/* Out of the 940px wrap and over to the window edge: inside the wrap it stopped
   170px short of the corner on a wide screen and read as floating. */
.fifty{position:absolute;right:26px;top:50%;transform:translateY(-50%);
       font-family:Yellowtail,cursive;font-size:52px;line-height:1;
       color:var(--gold);white-space:nowrap}
@media (max-width:1100px){ .fifty{display:none} }
.nav a{color:var(--ground)}
.nav a.on{color:var(--gold)}
/* Home: a house, first in the pinned row, so the way back is always on screen
   (the masthead links home too, but nothing says so). James, 2026-09-25. */
.nav a.home,.mnav a.home{display:inline-flex;align-items:center}
.nav a.home svg{display:block}

/* hero */
.hero{text-align:center;padding:44px 0 10px}
/* "Having trouble?" for someone reading through a Join request (index.html) */
.trouble{max-width:620px;margin:0 auto 26px;padding:14px 18px;text-align:left;
  background:#fff8e3;border:2px solid var(--gold,#e8b431);border-radius:6px;font-size:16px}
.trouble p{margin:0 0 8px}
.trouble summary{cursor:pointer;font-weight:700;color:var(--red);font-size:17px}
.trouble form{margin-top:10px}
.trouble label{display:block;font-size:14px;margin-bottom:4px}
.trouble textarea{width:100%;box-sizing:border-box;font:inherit}
.trouble .btn{margin-top:8px}
.eyebrow{font-size:13px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
         color:var(--red);margin-bottom:12px}
/* 15ch was the cap here, and that is fifteen CHARACTERS - so a 47-character
   headline broke into three short lines while the cards below it used the whole
   940px. James, 2026-09-05: "we use plenty of the screen for the lower part but
   wrap the text on the upper part."
   24ch gives this headline two lines and still stops a longer one sprawling
   across a wide monitor; text-wrap:balance evens the lines. Every other page
   sets max-width:none on its own h1, so this governs the home page only. */
h1{font-family:'Source Serif 4',Georgia,serif;font-size:48px;line-height:1.08;font-weight:700;
   margin:0 auto 16px;max-width:24ch;text-wrap:balance}
.lede{font-size:19px;color:var(--dim);margin:0 auto 26px;max-width:56ch}
.btns{display:flex;gap:13px;justify-content:center;flex-wrap:wrap}
.btn{background:var(--red);color:#fff;padding:13px 26px;border-radius:3px;font-weight:700;
     display:inline-flex;align-items:center;justify-content:center;min-height:44px}
.btn:hover{background:#c8102e;color:#fff;text-decoration:none}
/* Pressed and working states, so a click is visibly received - an admin action
   takes a second or two on NS before the page comes back. James, 2026-09-15. */
button.btn{cursor:pointer;font:inherit;font-weight:700}
.btn{transition:background-color .12s ease,transform .06s ease}
.btn:active{transform:translateY(1px);filter:brightness(.85)}
.btn[aria-busy="true"],.btn:disabled{opacity:.6;cursor:progress;transform:none;filter:none}
.btn.ghost{background:transparent;border:1.5px solid #c9c3b8;color:var(--ink);font-weight:600}
/* The reunion, in the theme gold (James, 2026-09-25). Dark text: white on this
   gold is too faint to read. */
.btn.gold{background:var(--gold);color:var(--dark)}
.btn.gold:hover{background:#d9a21c;color:var(--dark)}
.btn.dark{background:var(--dark);color:#fff}
.btn.dark:hover{background:#3a3631;color:#fff}
/* Words in the hero that go somewhere say so - a red word alone reads as emphasis. */
.hero .lede a,.comingsoon a{text-decoration:underline}
.note{font-size:14px;color:var(--faint);margin-top:14px}
.comingsoon{margin-top:20px;font-size:19px;line-height:1.4;font-weight:600;
  color:var(--dim);letter-spacing:.01em}
@media (max-width:640px){.comingsoon{font-size:17px}}

figure{margin:34px 0 0;text-align:center}
figure img{width:100%;max-width:500px;border:8px solid #fff;box-shadow:0 2px 14px rgba(0,0,0,.16)}
figcaption{font-size:14px;color:var(--faint);margin-top:10px;font-style:italic}
/* The reunion mark is line art on a transparent ground, not a photograph:
   no white mat, no drop shadow. */
figure.mark img{max-width:620px;border:0;box-shadow:none}

/* cards + tables */
.cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:40px}
/* The home page has four: a row of four when there is room, two by two when not */
.cards.four{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1100px){.cards.four{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Six cards: two rows of three, then two a row (2026-10-02). */
.cards.four.six{grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:1100px){.cards.four.six{grid-template-columns:repeat(2,minmax(0,1fr))}}
.cards.four.six{gap:14px}
.cards.four.six .card{padding:12px 14px}
.cards.four.six .card .n{font-size:28px}
.cards.four.six .card .l{font-size:14px;margin:5px 0 3px}
.cards.four.six .card p{font-size:13px;line-height:1.4}
.card{background:var(--panel);border:1px solid var(--line);border-radius:4px;padding:22px}
.card .n{font-family:'Source Serif 4',Georgia,serif;font-size:34px;font-weight:700;color:var(--red);line-height:1}
.card .l{font-size:15px;font-weight:600;margin:7px 0 5px}
.card p{font-size:14px;color:var(--faint);margin:0}

h2{font-family:'Source Serif 4',Georgia,serif;font-size:26px;font-weight:700;margin:44px 0 20px}
.rows{display:flex;flex-direction:column}
.row{display:flex;gap:22px;align-items:baseline;padding:14px 4px;border-bottom:1px solid var(--line)}
.row .yr{font-family:'Source Serif 4',Georgia,serif;font-size:21px;font-weight:700;width:96px;flex-shrink:0}
.row .mid{flex-grow:1}
.muted{color:var(--faint)}

/* directory */
.tools{display:flex;gap:11px;flex-wrap:wrap;align-items:center;margin:0 0 20px}
.search{position:relative;flex-grow:1;min-width:250px}
.search input{width:100%;padding:12px 14px 12px 40px;font:inherit;font-size:15px;
              border:1.5px solid #d6d0c5;border-radius:4px;background:#fff;min-height:44px}
.search svg{position:absolute;left:14px;top:14px}
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{background:#fff;border:1.5px solid #d6d0c5;padding:11px 16px;border-radius:999px;
      font-size:14px;font-weight:600;color:var(--ink);min-height:44px;display:inline-flex;align-items:center}
.chip.on{background:var(--ink);border-color:var(--ink);color:#fff}
.chip:hover{text-decoration:none}
/* The chips are <button> now rather than <a>, so they need the type reset that
   a link never needed. */
button.chip{font-family:inherit;cursor:pointer}
.search-go{min-height:44px;padding:11px 20px;cursor:pointer}

table{width:100%;border-collapse:collapse;background:var(--panel);
      border:1px solid var(--line);border-radius:4px;overflow:hidden}
thead th{background:#efeae0;border-bottom:1px solid var(--line);text-align:left;padding:12px 16px;
         font-size:12px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
tbody td{padding:13px 16px;border-bottom:1px solid #eee9df;font-size:15px;vertical-align:top}
tbody tr:nth-child(even) td{background:#faf8f4}
tbody tr:last-child td{border-bottom:0}
.private{color:#8b8479;font-style:italic;display:inline-flex;align-items:center;gap:6px}

.pager{display:flex;justify-content:space-between;align-items:center;margin-top:18px;
       font-size:15px;color:var(--dim);flex-wrap:wrap;gap:12px}
.pager .pages{display:flex;gap:7px;flex-wrap:wrap}
.pager a,.pager span.cur{min-width:40px;min-height:40px;display:inline-flex;align-items:center;
       justify-content:center;border-radius:4px;font-weight:600;padding:0 12px}
.pager a{background:#fff;border:1.5px solid #d6d0c5;color:var(--ink)}
.pager span.cur{background:var(--ink);color:#fff}

.consent{background:#fdf8e9;border:1px solid #e6d59c;border-radius:4px;padding:16px 19px;
         margin-top:24px;display:flex;gap:13px;align-items:flex-start;font-size:15px;color:#4a3f1d}
.consent svg{flex-shrink:0;margin-top:3px}

dl.facts{display:grid;grid-template-columns:150px 1fr;gap:0;margin:0}
dl.facts dt{padding:12px 0;border-bottom:1px solid var(--line);font-weight:600;color:var(--faint);font-size:14px}
dl.facts dd{padding:12px 0;border-bottom:1px solid var(--line);margin:0}

footer.site{background:var(--dark);color:#b9b2a7;margin-top:46px;font-size:14px}
footer.site .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px;
                  padding-top:26px;padding-bottom:26px;flex-wrap:wrap}
footer.site img{width:30px}
/* The page-wide link colour is a red made for a cream background; on the dark
   footer it reads as a warning rather than a link. */
footer.site a{color:#d8d2c7;text-decoration:underline}
footer.site a:hover{color:#fff}
.bee{display:flex;align-items:center;gap:11px}
/* The footer mark is the seal now, not the old bee gif, which came in at its
   own 120px. Pin it so the footer keeps its proportions. */
.bee img{width:34px;height:auto}

@media (max-width:760px){
  h1{font-size:31px}
  .lede{font-size:17px}
  .cards{grid-template-columns:1fr}
  /* The home page's four numbers, two to a row and snug, not four tall boxes.
     James, 2026-09-30: "These boxes waste space. Can we put 2 per row? And
     less white border space." */
  .cards.four{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:24px}
  .cards.four .card{padding:12px 12px 13px}
  .cards.four .card .n{font-size:28px}
  .cards.four .card .l{font-size:14px;line-height:1.25;margin:5px 0 4px}
  .cards.four .card p{font-size:13px;line-height:1.4}
  .btns{flex-direction:column}
  .btn{width:100%}
  dl.facts{grid-template-columns:1fr}
  dl.facts dt{padding-bottom:0;border-bottom:0}
}
/* Tables become a stacked list on a phone held upright only. Turned sideways,
   Safari keeps clear of the camera cutout and leaves ~730-750pt - under 760, so
   landscape got the list too. James, 2026-10-22: tables on every page. */
@media (max-width:760px) and (orientation:portrait){
  table thead{display:none}
  table,tbody,tbody tr,tbody td{display:block;width:100%}
  tbody tr{border-bottom:1px solid var(--line);padding:6px 0}
  tbody td{border-bottom:0;padding:4px 16px}
  tbody td::before{content:attr(data-l);display:block;font-size:12px;font-weight:700;
                   letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
}

/* What went wrong, beside the box it is about rather than only in the banner
   at the top - which is easy to miss when the form comes straight back.
   James, 2026-09-21. */
.problem{display:block;margin:0 0 6px;padding:8px 12px;border-radius:4px;
         background:#fdeceb;border:1px solid #e3b3ae;color:#7d2018;
         font:600 15px/1.45 "Source Sans 3",Arial,sans-serif}
/* Likes. A quiet outline until it is yours, then the class red - the point is
   to be countable at a glance, not to shout. James, 2026-09-21. */
.likes{margin:8px 0 0}
.like{display:inline-flex;align-items:center;gap:7px;background:none;cursor:pointer;
      border:1px solid var(--line);border-radius:999px;padding:5px 13px;
      font:600 14px/1 "Source Sans 3",Arial,sans-serif;color:var(--dim)}
.like:hover{border-color:var(--red);color:var(--red)}
.like.on{border-color:var(--red);color:var(--red);background:#fdeceb}
.like.static{cursor:default}
.like.static:hover{border-color:var(--line);color:var(--dim)}
.like .n{font-weight:700}
.likes a{margin-left:10px;font-size:14px}
/* The count sits beside the heart and opens the list of names. A button, not a
   link: it goes nowhere. James, 2026-09-21. */
.likes .who{background:none;border:0;cursor:pointer;padding:5px 6px;margin-left:2px;
            font:700 14px/1 "Source Sans 3",Arial,sans-serif;color:var(--dim)}
.likes .who:hover,.likes .who[aria-expanded="true"]{color:var(--red);text-decoration:underline}
/* An opened log record keeps its line breaks - a page of SQL run together is
   unreadable. James, 2026-09-21. */
.log .ll .more{display:block;white-space:pre-wrap;margin-top:6px}

.likedby{display:block;margin:6px 0 0;font-size:14px;color:var(--dim);max-width:52ch}
.likedby[hidden]{display:none}
.likedby .lk-more{background:none;border:0;padding:0;font:inherit;color:var(--red);
  cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.likedby .lk-all{display:block;max-height:9em;overflow-y:auto;padding-right:6px}
.likedby .lk-all[hidden],.likedby .lk-short[hidden]{display:none}

/* flash, forms, guestbook */
.flash{background:#e8f2df;border:1px solid #b6cfa4;border-radius:4px;padding:12px 16px;
       margin:20px 0 0;font-size:15px}
.form p{margin:0 0 15px}
.form label{display:block;font-size:14px;font-weight:600;color:var(--dim);margin-bottom:5px}
/* a value shown, not asked - the guestbook's address when signed in (2026-10-01) */
.form .label{display:block;font-size:14px;font-weight:600;color:var(--dim);margin-bottom:5px}
.form .myaddr{display:block;font-size:17px;padding:4px 0}
.form .myaddr .muted{font-size:14px}
.form input[type=text],.form input[type=email],.form input[type=password],.form input[type=tel],.form select,.form textarea{
  width:100%;padding:11px 13px;font:inherit;font-size:16px;border:1.5px solid #d6d0c5;
  border-radius:4px;background:#fff;min-height:44px}
.form textarea{min-height:130px;resize:vertical}
/* A number and its type side by side, close and the same size (2026-09-30) */
.form .pair{display:flex;flex-wrap:wrap;gap:0 12px}
.form .pair > p{flex:0 1 15em;min-width:0}
.form .two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 16px}
/* First, Last, and a narrow Suffix on one line (2026-09-30) */
.form .two.with-suffix{grid-template-columns:minmax(0,1fr) minmax(0,1fr) 6.5em}
.form button{font:inherit;border:0;cursor:pointer}
.hint{display:block;font-size:13px;color:var(--faint);margin-top:5px;font-weight:400}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.fs{border:1px solid var(--line);border-radius:4px;padding:16px 18px;margin:0 0 18px;background:#fff}
.ver{margin-top:6px;font-size:11.5px;letter-spacing:.04em;opacity:.55}
/* Teal, not red. Red is what this site uses to say something is WRONG - a failed
   contact message, a send in trouble, "every one of these addresses is real" - and a
   permanent red bar across the top of the development copy spends that signal on a
   fact that is merely true. Teal matches the dev favicon (the teal D), so the tab and
   the page agree about which copy you are on. James, 2026-09-22. */
/* Frozen at the top, just under the pinned menu row - and under the scrolling
   reunion banner when that is showing (_reunion_banner.html moves it down). At
   every width: it used to stop being sticky on a phone. James, 2026-09-27. */
.devbar{position:sticky;top:50px;z-index:56;background:repeating-linear-gradient(
    135deg,#14636b,#14636b 14px,#105159 14px,#105159 28px);
  color:#fff;font-size:13.5px;line-height:1.45;padding:9px 16px;text-align:center;
  box-shadow:0 1px 0 rgba(0,0,0,.25)}
.devbar strong{letter-spacing:.06em;text-transform:uppercase}
.devbar a{color:#fff;text-decoration:underline;margin-left:6px}
.noface{display:flex;align-items:center;justify-content:center;width:96px;height:130px;
  border-radius:4px;background:#e8e2d6;color:#9a9187;font-size:26px;font-weight:600;
  letter-spacing:.04em;border:1px solid var(--line)}
.gbbar{position:sticky;top:0;z-index:40;background:var(--ground);padding:12px 0 10px;
  margin:0 0 4px;border-bottom:1px solid var(--line)}
.gbsearch{display:flex;gap:8px;align-items:center}
.gbsearch input[type=search]{flex:1;min-width:0;padding:10px 13px;font:inherit;font-size:16px;
  border:1.5px solid #d6d0c5;border-radius:4px;background:#fff;min-height:44px}
.gbsearch .btn{white-space:nowrap}
/* Not full width on a phone: the site-wide .btn{width:100%} squeezed the search
   box beside it down to nothing. James, 2026-09-14. */
@media (max-width:760px){.gbsearch .btn{width:auto;flex:0 0 auto;padding:10px 16px}}
/* a little air between the intro and the search box, on a phone (2026-10-01) */
@media (max-width:760px){.gbbar{margin-top:6px}}
.gbsearch .clear{font-size:14px;color:var(--dim);white-space:nowrap}
.gbbar .found{margin:8px 0 0;font-size:14px;color:var(--dim)}
/* On the development box the dev banner is pinned under the menu (50px) - sit below it. */
body:has(.devbar) .gbbar{top:88px}
/* On the development box the red banner is sticky too. Sit below it rather than
   under it - both would otherwise pin themselves to the top and overlap. */
/* --bg was never defined, so until 2026-09-18 this bar was see-through and the
   notes showed through it as you scrolled. --ground is the page colour. */
.azjump{display:flex;flex-wrap:wrap;gap:2px;margin:0 0 14px}
.az{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:30px;
  padding:0 6px;border-radius:4px;font-size:14px;font-weight:600;color:var(--dim);
  text-decoration:none;border:1px solid transparent}
.az:hover{background:#efeae0;border-color:var(--line)}
.az.on{background:var(--ink,#3a352d);color:#fff}
.az.off{color:#cdc6ba;font-weight:400}
.gbsort{display:flex;gap:14px;margin:9px 0 0;font-size:14px;align-items:center;flex-wrap:wrap}
.gbsort a{color:var(--dim);text-decoration:none;border-bottom:1.5px solid transparent;padding-bottom:1px}
.gbsort a.gbtop{font-weight:600;color:var(--ink,#3a352d)}
.gbsort a.gbtop[hidden]{display:none}
.gbsort a.gbadd{margin-left:auto;padding:10px 28px;font-size:16px;width:auto;min-width:180px;text-align:center;color:#fff;border-bottom:0}
.gbsort a.on{color:var(--ink,#3a352d);font-weight:600;border-bottom-color:currentColor}
/* Guestbook highlights (2026-10-01): a folded box above the search bar */
.gbhl{margin:0 0 12px;border:1px solid #e6d29c;border-radius:4px;background:#fbf6e8;padding:10px 14px}
.gbhl summary{cursor:pointer;font-weight:600}
.gbhl ul{margin:10px 0 2px;padding-left:20px;display:flex;flex-direction:column;gap:6px;font-size:15.5px;line-height:1.4}
.gbhl .hl-one summary{font-weight:400;list-style-position:outside}
.gbhl .hl-t{font-weight:600}
.gbhl .hl-note{margin:8px 0 10px;padding:10px 12px;background:#fff;border:1px solid var(--line);border-radius:4px}
.gbhl .hl-note .msg{margin-top:0}
.gbhl .hl-more{margin:6px 0 0;font-size:14px}
.gbhl .hl-all{margin:10px 0 0;font-size:14.5px}
.gbhl-head{font-size:16px}
.hl-why{margin:0 0 6px;font-size:14px;font-weight:600;color:#7a5a12}
.gbhl-admin{margin-top:8px;font-size:14px}
.gbhl-admin summary{cursor:pointer;color:var(--dim)}
.gbhl-admin form{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.gbhl-admin input[type=text]{flex:1 1 260px;padding:7px 9px;font:inherit;font-size:14px;border:1px solid var(--line);border-radius:4px}
.gbhl-admin .btn{width:auto;padding:6px 14px;font-size:14px}
/* On a phone "Add your own" sits on the sort line, not under it (James, 2026-10-01).
   After the .gbsort rules above, or they win: same specificity, later wins. */
@media (max-width:760px){.gbsort{flex-wrap:nowrap;gap:10px}.gbsort a{white-space:nowrap}.gbsort a.gbadd{min-width:0;padding:7px 12px;font-size:14px}}
.jobs{margin:0 0 16px;border:1px solid var(--line);border-radius:5px;background:#fff;
  padding:12px 14px}
.jobs summary{cursor:pointer;font-weight:600;font-size:15px;color:var(--dim)}
.jobgrid{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.job{display:flex;align-items:baseline;gap:7px;padding:7px 11px;border:1px solid var(--line);
  border-radius:4px;text-decoration:none;background:#faf8f4}
.job:hover{background:#f1ece2}
.job.on{background:var(--ink,#3a352d);border-color:var(--ink,#3a352d)}
.job.on .n,.job.on .lab{color:#fff}
.job .n{font-weight:700;font-size:16px;color:var(--ink,#3a352d)}
.job .lab{font-size:13.5px;color:var(--dim)}
.job.other .n{color:var(--faint)}
tr.you{background:#fdf7e3}
/* In Memory, on the class list - James, 2026-09-14 */
a.died strong{font-style:italic;font-weight:600}
tr.you td{border-color:#e8dcae}
.youtag{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:9px;font-size:11px;
  font-weight:700;letter-spacing:.07em;text-transform:uppercase;background:#e8b431;color:#3a352d}
/* the 1977 yearbook pages on a class-list row (2026-10-01) */
.ybp{font-size:13px;margin-top:2px}
/* styled like the WHERE / OCCUPATION labels on a phone (2026-10-01) */
.yblbl{margin-right:6px;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.reunionrow{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0 0 8px}
.rblock{display:flex;flex-direction:column;gap:6px}
.rblock .arch{flex:1}
.rblock .yr{display:block;font-size:13px;color:var(--faint);letter-spacing:.04em;margin-top:2px}
.rblock .sub{display:block;padding:8px 12px;border:1px solid var(--line);border-radius:4px;
  background:#faf8f4;font-size:14px;color:var(--dim);text-decoration:none}
.rblock .sub:hover{background:#f1ece2}
.rblock .sub::before{content:"\21B3";margin-right:7px;color:var(--faint)}
@media (max-width:700px){.reunionrow{grid-template-columns:1fr}}
pre.log, div.log{margin:0;padding:12px 14px;background:#f7f5f1;border:1px solid var(--line);
  border-radius:4px;font-size:12.5px;line-height:1.55;overflow-x:auto;white-space:pre;
  max-height:420px;overflow-y:auto}
/* The error log, line by line: a long one is cut with a summary you can open,
   and what opens wraps instead of running off the side. 2026-09-19. */
/* Out to the edges of the box it sits in, so it lines up with the footer
   rather than being inset by the fieldset's padding as well as the page's.
   James, 2026-09-19: "the error log should be the same width as the footer". */
div.log{font-family:ui-monospace,Menlo,Consolas,monospace;
  margin:0 -18px -16px;border-left:0;border-right:0;border-radius:0 0 4px 4px}
div.log .ll{white-space:pre-wrap;word-break:break-word}
div.log details.ll>summary{cursor:pointer;white-space:pre;overflow:hidden;
  text-overflow:ellipsis;color:inherit}
div.log details.ll[open]>summary{color:var(--faint);white-space:pre-wrap;overflow:visible}
/* The first line stays beside the triangle when open, in full rather than cut
   short, and the body below holds only what comes AFTER it - the first line was
   being shown truncated AND again in full underneath. James, 2026-09-22:
   "expands, does exactly that", then "keep the 1st line of text on the same
   line with the triangle". */
div.log details.ll>summary>.whole{display:none}
div.log details.ll[open]>summary>.cut{display:none}
div.log details.ll[open]>summary>.whole{display:inline}
.fs legend{font-size:13px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
           color:var(--faint);padding:0 6px}
.addr{font-size:15px;padding:3px 0}
.check label{display:flex;gap:10px;align-items:flex-start;font-weight:400;font-size:15px;
             color:var(--ink);cursor:pointer;min-height:44px;align-items:center}
.check input{width:19px;height:19px;flex-shrink:0}

.entries{display:flex;flex-direction:column;gap:0;margin-top:8px}
/* Alternate shading. Entries run to very different lengths - a two-line hello
   next to a six-paragraph life story - so a rule alone leaves it hard to see
   where one ends and the next begins. */
.entry{border-bottom:1px solid var(--line);padding:20px 18px;
       border-radius:3px 3px 0 0}
.entry:nth-child(odd){background:#efeade}
.entry .msg{margin:0 0 9px;font-size:16px;line-height:1.6;white-space:pre-line}
.entry .by{margin:0;font-size:14px;color:var(--dim)}
@media (max-width:760px){ .form .two, .form .two.with-suffix{grid-template-columns:1fr} }

/* guestbook year rail — bar height is that year's volume, so the reunion
   years (1997, 2002, 2007) announce themselves without needing a label */
.years{display:flex;align-items:flex-end;gap:4px;flex-wrap:wrap;margin:22px 0 6px;
       padding:0 0 4px;border-bottom:2px solid var(--line)}
.years .yr{display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
           gap:5px;min-width:34px;min-height:44px;padding:4px 3px 2px;border-radius:3px 3px 0 0;
           text-decoration:none;color:var(--faint)}
.years .yr:hover{background:#eae4d8;text-decoration:none}
.years .yr .bar{display:block;width:16px;background:#cdc5b6;border-radius:2px 2px 0 0}
/* Off the scale (the reunion years): taller than any other bar, with a darker
   top to say it goes on past the chart. */
.years .yr .bar.peg{background:linear-gradient(#8a7f6c 0 28%,#cdc5b6 28%)}
.years .yr .lab{font-size:12px;font-weight:600;letter-spacing:.02em}
.years .yr.on{background:var(--ink)}
.years .yr.on .bar{background:var(--gold)}
.years .yr.on .lab{color:#fff}
@media (max-width:560px){ .years .yr{min-width:28px} .years .yr .bar{width:12px} }

/* photographs — a plain grid, replacing the dialup-era thumbnail-then-page-per-photo */
.albums{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:18px;margin:0 0 10px}
.album{display:flex;flex-direction:column;gap:9px;text-decoration:none;color:var(--ink)}
.album:hover{text-decoration:none}
.album .shot{display:block;aspect-ratio:4/3;overflow:hidden;border-radius:4px;background:#e4ded2;
             border:1px solid var(--line)}
/* Crop from the TOP, never the centre. These are photographs of people and the
   heads are in the top third; a centred crop takes them off. */
.album .shot img{width:100%;height:100%;object-fit:cover;object-position:center top;
                 display:block;transition:transform .25s ease}
.album:hover .shot img{transform:scale(1.04)}
.album .meta{display:flex;flex-direction:column;gap:1px;font-size:15px}
.album .meta .muted{font-size:13px}

/* Masonry columns, NOT square tiles. A square tile with object-fit:cover
   centre-crops, and in a photo of people the heads are in the top third - so
   57 portraits were being decapitated. Natural aspect ratio, nothing cropped.
   max-width on each img is its own native width, so the 21 photos under 150px
   are shown at their real size instead of being stretched into mush. */
.grid{column-count:4;column-gap:10px;margin:20px 0 0}
.cell{break-inside:avoid;margin:0 0 10px;padding:0;border:1px solid var(--line);
      background:#e4ded2;border-radius:3px;overflow:hidden;cursor:zoom-in;display:block;
      width:100%;text-align:center}
.cell img{width:100%;height:auto;display:block;margin:0 auto;transition:transform .25s ease}
.cell:hover img{transform:scale(1.03)}
.cell:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
@media (max-width:1000px){ .grid{column-count:3} }
@media (max-width:680px){ .grid{column-count:2} }
@media (max-width:380px){ .grid{column-count:1} }

/* Above the pinned menu, banner and dev bar (57-70), which covered its top
   edge - the way back and the close button with it. */
.lb{position:fixed;inset:0;z-index:100;background:rgba(16,15,13,.94);display:flex;
    flex-direction:column;align-items:center;justify-content:center;padding:54px 66px}
/* display:flex above beats the browser's default [hidden]{display:none}, so the
   overlay would sit on top of the page permanently. It must be said explicitly. */
.lb[hidden]{display:none}
/* The caption sits just under the photo (James, 2026-09-29), so the photo
   leaves room for it. */
.lb-img{max-width:100%;max-height:calc(100% - 40px);min-height:0;object-fit:contain;display:block;
        box-shadow:0 6px 40px rgba(0,0,0,.6)}
.lb-cap{flex:none;margin-top:12px;text-align:center;color:#cdc7bc;
        font-size:14px;padding:0 20px}
.lb-close{position:absolute;top:12px;right:14px}
/* the album's name over the full-size view, and each photo's file name */
.lb .lb-head{position:absolute;top:12px;left:12px;max-width:calc(100% - 90px);color:#e8e3da;
         font:600 17px/1.3 var(--serif,Georgia,serif);white-space:nowrap;overflow:hidden;
         text-overflow:ellipsis;border-radius:6px;padding:10px 12px;text-align:left}
.lb-cap strong{color:#f2efe9;font-weight:600}
.cell .fname{display:block;padding:3px 6px 4px;font-size:11px;line-height:1.3;
    color:var(--dim);background:#fff;border-top:1px solid var(--line);overflow-wrap:anywhere}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%)}
.lb-prev{left:8px} .lb-next{right:8px}
.lb button,.lb-close{background:transparent;border:0;color:#e8e3da;cursor:pointer;padding:10px;
                     min-width:44px;min-height:44px;border-radius:50%}
.lb button:hover,.lb-close:hover{background:rgba(255,255,255,.12);color:#fff}
@media (max-width:600px){
  .lb{padding:52px 6px}
  .lb-nav{top:auto;bottom:52px;transform:none}
  .grid{column-gap:6px}
}

/* admin */
.adminbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:18px 0 6px;
          padding:12px 14px;background:#efeae0;border:1px solid var(--line);border-radius:4px}
.adminbar .btn{padding:10px 18px;font-size:15px}
.pickall{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;
         min-height:44px;cursor:pointer;margin-right:auto}
.pickall input{width:19px;height:19px}
.grid.admin .cell,.dupgroup .cell{position:relative;cursor:pointer}
.grid.admin .cell input,.dupgroup .cell input{position:absolute;top:8px;left:8px;z-index:2;
    width:22px;height:22px;cursor:pointer;accent-color:#9a2313}
.cell .tag{position:absolute;left:6px;bottom:6px;background:rgba(16,15,13,.82);color:#f2efe9;
    font-size:11px;font-weight:600;padding:3px 6px;border-radius:3px;letter-spacing:.02em}
.cell .tag.dup{left:auto;right:6px;background:#9a2313}
.cell .tag.off{left:auto;right:6px;bottom:auto;top:6px;background:#3c3833}
.cell .tag.best{left:auto;right:6px;top:6px;bottom:auto;background:#2d6a2d}
.cell .tag.album{bottom:26px;background:rgba(16,15,13,.62);font-weight:400}
/* The name under a committee headshot. Part of the tile rather than an overlay:
   these scans are ~100px across and anything laid over them covers a face. */
a.cell{cursor:pointer;text-decoration:none;color:inherit}
a.cell:hover .who{text-decoration:underline}
.person a{text-decoration:none;color:inherit;display:block}
/* the name under a linked headshot reads as a link: it goes to their class-list entry */
.person a figcaption{color:var(--red);text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px}
.person a:hover figcaption{text-decoration-thickness:2px}
.cell .who{display:block;padding:7px 6px 8px;font-size:13px;line-height:1.35;
    color:var(--ink);background:#fff;border-top:1px solid var(--line);
    text-align:center;font-family:var(--serif,Georgia,serif)}
.cell.is-hidden img{opacity:.32;filter:grayscale(1)}
.cell.lesser{outline:2px solid #c8a23a;outline-offset:-2px}
.dupgroup{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-start;
          padding:12px;margin:0 0 12px;background:#fff;border:1px solid var(--line);border-radius:4px}
.dupgroup .cell{width:190px;flex:0 0 auto}

/* archive index + the old pages themselves */
.archlist{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:12px;margin-bottom:8px}
.arch{display:flex;flex-direction:column;gap:3px;padding:15px 17px;background:#fff;
      border:1px solid var(--line);border-radius:4px;color:var(--ink);text-decoration:none}
.arch:hover{border-color:#c9c3b8;background:#fffdf8;text-decoration:none}
.arch strong{color:var(--red);font-size:16px}
.arch .muted{font-size:14px;line-height:1.45}

/* The old markup is 1997 table layout. Contain it and make it legible without
   pretending it is modern; it should still read as a page of its time. */
.oldpage{background:#fff;border:1px solid var(--line);border-radius:4px;padding:26px 28px;
         margin-top:18px;overflow-x:auto;font-size:16px;line-height:1.6}
.oldpage table{width:auto;max-width:100%;border:0;background:transparent}
.oldpage td,.oldpage th{border:0;padding:4px 8px;background:transparent!important;font-size:inherit;
                        text-transform:none;letter-spacing:normal;color:inherit}
.oldpage th{font-weight:700}
.oldpage img{max-width:100%;height:auto}
/* The committee headshots are 96-100px scans from 1997-2002 and the old pages
   hard-code those dimensions, so on a modern screen they came out postage-stamp
   sized. Nothing larger survives, so this trades a little sharpness for being
   able to see a face - 168px matches the 132px-wide treatment the /committee
   page already gives the same photographs.
   Scoped by src so only these grow: the FAQ banner and the other archive images
   are the size their pages intend. James, 2026-09-05. */
.oldpage img[src*="committee_photos"]{width:124px;height:164px;object-fit:cover;
  object-position:center top;max-width:none;border:1px solid var(--line);background:#fff;
  vertical-align:top}
/* A uniform box, not just a uniform height. The scans run 91-100 wide by 125-148
   tall, so fixing the height alone left every photograph a different width and
   the rows came out ragged. object-position:center top because cover-cropping a
   portrait from the middle takes the head off - the photo grid taught us that
   once already. */
.oldpage td{vertical-align:top}
.oldpage h1,.oldpage h2,.oldpage h3{font-family:'Source Serif 4',Georgia,serif;margin:18px 0 10px}
.oldpage h1{font-size:26px} .oldpage h2{font-size:21px} .oldpage h3{font-size:18px}
.oldpage hr{border:0;border-top:1px solid var(--line);margin:18px 0}
.oldpage center{text-align:left}
.oldpage p{margin:0 0 12px}

/* committee headshots: every one the same size - the size the 1997 scans were
   (Wanda Le Protti-Watts's, 96x130) - whether it is an old scan or a class-list
   portrait shown in its place. Filled from the top so no head is cut off. */
.people{display:flex;flex-wrap:wrap;gap:18px;margin:20px 0 10px}
.person{margin:0;width:132px;display:flex;flex-direction:column;gap:7px;align-items:center;text-align:center}
.person img{width:96px;height:130px;object-fit:cover;object-position:center top;
  border:1px solid var(--line);border-radius:3px;background:#fff}
.person figcaption{font-size:13px;line-height:1.4;color:var(--ink)}
/* Someone the old page listed with no photograph. Given the same footprint as
   the others so the row still lines up, rather than being left out. */
.person.nopic{justify-content:flex-end;min-height:132px}
.person.nopic figcaption{padding-bottom:2px}
.person figcaption .muted{font-size:12px}

/* the invitation to sign in, and the claims queue */
.invite{display:flex;gap:16px;align-items:center;justify-content:space-between;flex-wrap:wrap;
        background:#fdf8e9;border:1px solid #e6d59c;border-radius:4px;padding:16px 19px;margin:0 0 20px}
.invite strong{display:block;font-size:15px;color:#4a3f1d}
.invite span{font-size:14px;color:#6b5c2c;max-width:62ch;display:block;margin-top:2px}
.invite .btn{flex-shrink:0}
.claim{background:#fff;border:1px solid var(--line);border-radius:4px;padding:16px 18px;margin:0 0 12px}
.claim.done{opacity:.6}
.claim .who{font-size:16px;margin-bottom:4px}
.claim .tagline{background:var(--ink);color:#fff;font-size:11px;font-weight:700;padding:2px 7px;
                border-radius:3px;text-transform:uppercase;letter-spacing:.06em;margin-left:6px}
/* The admitted state is the one card still waiting on somebody, so it is drawn
   open: the tag names the state instead of shouting APPROVED in black. */
.claim .tagline.open{background:var(--gold);color:var(--ink);font-weight:600;letter-spacing:0}
/* A matched entry that has been deleted - the card used to name it as though it
   were live, which is what Attach would then have acted on. */
.claim .gone{color:var(--red)}
/* A stranger's view of a portrait: 38 pixels drawn at 164, which the browser
   smooths into a face-shaped impression. The file really is that small - the
   blur is not a filter over a full-size picture, which anyone could strip. */
.yb-blur{width:164px;height:230px;object-fit:cover;object-position:center top;
  border:1px solid var(--line);border-radius:3px;background:#f4f1ea;display:block}
.yb-none{width:164px;height:230px;font-size:40px}
/* Beside the name at the top of an entry, so a deleted one says so where you are
   looking rather than only in the block at the foot of the page. Admin view
   only - nobody ever reads this on their own entry. James, 2026-09-23. */
.delmark{color:var(--red);font-family:"Source Sans 3",Arial,sans-serif;
  font-size:15px;font-weight:600;font-style:normal;white-space:nowrap}
.claim .note-text{margin:6px 0;font-size:15px;line-height:1.5;background:#faf8f4;
                  border-left:3px solid var(--line);padding:8px 12px}
.claimacts{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.claimacts .btn{padding:9px 16px;font-size:14px}
/* Attach to an entry by its number (2026-10-01) */
.claimacts .note-to{flex-basis:100%;display:flex;flex-direction:column;gap:4px;font-size:14px;color:var(--dim)}
.claimacts .note-to textarea{font:inherit;font-size:15px;padding:7px 9px;border:1px solid var(--line);border-radius:4px}
.claimacts .cy{display:inline-flex;align-items:center;gap:6px;font-size:14px;color:var(--dim)}
.claimacts .cy input{width:4.5em;padding:8px 8px;font:inherit;font-size:15px;border:1px solid var(--line);border-radius:4px}
.claimacts .maybe{flex-basis:100%;display:flex;flex-direction:column;gap:6px;font-size:14.5px}
.claimacts .maybe-one{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.claimacts .maybe-one .btn{padding:5px 12px;font-size:13px}
.claimacts .attachto{display:inline-flex;align-items:center;gap:6px;font-size:14px;color:var(--dim)}
.claimacts .attachto input{width:5.5em;padding:8px 9px;font:inherit;font-size:15px;margin-left:4px;border:1px solid var(--line);border-radius:4px}

/* photographer credits, in the yearbook's own idiom - the subject leads, the
   photographer is acknowledged underneath rather than filed under */
.credits{font-size:14px;color:var(--dim);margin:2px 0 0;max-width:70ch;line-height:1.5}
.credits strong{color:var(--ink);font-weight:600}

/* flagging duplicates from inside the gallery (admin only) */
.adminnote{margin:14px 0 0;padding:8px 12px;background:#f4efe3;border:1px solid var(--line);
  border-radius:4px;font-size:13px;color:#5c554b}
.adminnote kbd{background:#fff;border:1px solid var(--line);border-bottom-width:2px;
  border-radius:3px;padding:0 5px;font:600 11px/1.6 ui-monospace,Menlo,monospace}
.grid.hasflags .cell{position:relative}
.cell .tag.dim{left:6px;bottom:6px;background:rgba(16,15,13,.72);font-weight:400}
.flagpip{position:absolute;top:6px;right:6px;width:26px;height:26px;line-height:26px;
  text-align:center;border-radius:50%;background:rgba(16,15,13,.55);color:#fff;font-size:14px;
  opacity:0;transition:opacity .15s ease,background .15s ease}
.cell:hover .flagpip,.cell:focus-visible .flagpip{opacity:1}
.flagpip:hover{background:#9a2313}
.cell.flagged{outline:3px solid #9a2313;outline-offset:-3px}
.cell.flagged .flagpip{opacity:1;background:#9a2313}
.lb-flag{position:absolute;top:14px;right:60px;width:40px;height:40px;border:0;cursor:pointer;
  border-radius:50%;background:rgba(255,255,255,.14);color:#fff;font-size:18px;line-height:40px;
  padding:0;z-index:3}
.lb-flag:hover{background:rgba(255,255,255,.28)}
.lb-flag.on{background:#9a2313}
@media (max-width:680px){ .flagpip{opacity:1} }

/* duplicates: tolerance picker and the paths under each group */
.thr{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:18px 0 0}
.thr .yr{padding:4px 10px;border:1px solid var(--line);border-radius:3px;font-size:13px;
  text-decoration:none;color:inherit;background:#fff}
.thr .yr.on{background:var(--ink);color:#f6f2e9;border-color:var(--ink)}
.thr .yr.on .muted{color:#c9c2b4}
.dupgroup{align-items:flex-start}
.dpath{flex:1 0 100%;margin:2px 0 0;font-size:11px;color:#8a8175;word-break:break-all}
.dpath code{font:inherit}
.cell .tag.orig{left:auto;right:6px;top:6px;bottom:auto;background:#2f5d86}
.cell.flagged .tag.best{right:auto;left:6px;top:6px;bottom:auto}

/* Album cards carry a nine-frame contact-sheet patch rather than one cover
   picture: a single frame tells you almost nothing about which reunion you
   are looking at, where nine of them tell you the room, the light and the
   decade at a glance. Cropped from the top, never the middle - these are
   photographs of people. */
.album .sheet{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;
  aspect-ratio:1;background:#26231f;padding:4px;border-radius:4px;overflow:hidden}
.album .sheet .fr{display:block;overflow:hidden;background:#15130f}
.album .sheet img{width:100%;height:100%;object-fit:cover;object-position:center top;
  display:block;transition:transform .3s ease}
.album:hover .sheet img{transform:scale(1.05)}
.album .sheet.n1,.album .sheet.n2,.album .sheet.n4{grid-template-columns:repeat(2,1fr)}
.album .sheet.n5,.album .sheet.n6{grid-template-columns:repeat(3,1fr)}

/* the photographer's name sits under their photograph, where it belongs */
.cell .by{display:block;padding:5px 8px 6px;font-size:11px;line-height:1.3;
  color:var(--dim);letter-spacing:.03em;text-align:left;background:#fbf9f5;
  border-top:1px solid var(--line);font-style:italic}

/* Walk the site as a member or a stranger sees it, without signing out and
   waiting on an emailed link to get back in. Only ever drawn for a real
   admin. Three faces, because they genuinely differ: a stranger is asked to
   sign in and refused the class list detail, a member is not. */
.adminpill{position:fixed;right:14px;bottom:14px;z-index:60;margin:0;display:flex;
  align-items:center;gap:0;background:#fff;border:1px solid var(--line);
  border-radius:20px;padding:4px 5px 4px 12px;box-shadow:0 2px 12px rgba(0,0,0,.16)}
.adminpill .lbl{font:500 10px/1 inherit;letter-spacing:.09em;text-transform:uppercase;
  color:#a49b8c;margin-right:9px}
.adminpill button{cursor:pointer;border:0;background:none;color:#6b6357;
  font:500 11px/1 inherit;letter-spacing:.04em;text-transform:uppercase;
  padding:6px 10px;border-radius:14px}
.adminpill button:hover{background:#f1ece0;color:var(--ink)}
.adminpill button.on{background:var(--ink);color:#f6f2e9}
.adminpill button.on:hover{background:#2f2b26;color:#f6f2e9}
@media print{ .adminpill{display:none} }
@media (max-width:560px){ .adminpill{right:8px;bottom:8px;padding-left:9px}
  .adminpill .lbl{display:none} .adminpill button{padding:6px 8px;font-size:10px} }

/* a link worth more than a line of text - the yearbook, and whatever else
   gets added beside it */
.linkcard{display:flex;gap:0;margin:22px 0 0;border:1px solid var(--line);
  border-radius:5px;background:#fbf9f5;overflow:hidden}
.linkcard .lk-body{padding:18px 20px}
.linkcard h2{margin:0 0 6px;font-size:20px}
.linkcard h2 a{text-decoration:none}
.linkcard h2 a:hover{text-decoration:underline}
.linkcard p{margin:0 0 8px;max-width:62ch;color:var(--dim);font-size:15px}
.linkcard p:last-child{margin-bottom:0}
.linkcard .src{font-size:12.5px;color:#8a8175}
.linkcard .src code{font:inherit;background:#f1ece0;padding:1px 5px;border-radius:3px}
.linkcard{align-items:stretch}
.linkcard .lk-cover{flex:0 0 300px;display:block;background:#e4ded2;line-height:0;
  border-right:1px solid var(--line)}
.linkcard .lk-cover img{width:100%;height:100%;object-fit:cover;object-position:center top}
@media (max-width:700px){
  .linkcard{flex-direction:column}
  .linkcard .lk-cover{flex:0 0 auto;border-right:0;border-bottom:1px solid var(--line)}
  .linkcard .lk-cover img{height:auto}
}

/* then and now: the yearbook portrait, and the photograph they add themselves */
.thennow{display:flex;gap:14px;margin:6px 0 18px;align-items:flex-start}
.thennow figure{margin:0}
/* 190px was sized to the 1977 scans, so a modern upload - James's is 839x900 -
   was shown at a fifth of its size and centre-cropped, which is why it looked
   like a thumbnail. 260px is still inside the yearbook crops' native height of
   270, so those stay sharp rather than being blown up, and the current
   photograph gets nearly twice the area. object-position stays center top: the
   photo grid taught us that cover-cropping portraits from the middle takes
   their heads off. James, 2026-09-05. */
.thennow img{display:block;width:auto;height:260px;object-fit:cover;object-position:center top;
  border:1px solid var(--line);border-radius:3px;background:#fff}
.thennow figcaption{font:italic 13px/1.6 var(--serif,Georgia,serif);color:var(--dim);
  text-align:center;margin-top:5px}
/* where a visitor would see someone's recent photograph: the same footprint, and why */
.recent-locked{display:flex;align-items:center;justify-content:center;box-sizing:border-box;
  width:195px;height:260px;padding:18px;text-align:center;border:1px dashed var(--line);
  border-radius:3px;background:#f3efe7;color:var(--dim);font-size:13.5px;line-height:1.5}
.recent-locked a{white-space:nowrap}
@media (max-width:560px){ .thennow img{height:190px} .recent-locked{width:143px;height:190px;padding:12px;font-size:12.5px} }

/* Class-list avatars. Only 44 of 333 have a 1977 portrait, so the empties get
   initials rather than a blank - a column that is mostly holes reads as broken,
   where a column of initials reads as a list. */
th.av{width:46px;padding-right:0}
td.av{width:46px;padding-right:0;vertical-align:middle}
td.av a{display:block;width:38px;height:38px;border-radius:50%;overflow:hidden;
  background:#e7e1d5;border:1px solid var(--line)}
td.av img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block}
td.av .ini{display:flex;width:100%;height:100%;align-items:center;justify-content:center;
  font:600 12px/1 inherit;letter-spacing:.03em;color:#8a8175}
@media (max-width:760px) and (orientation:portrait){ th.av{display:none} td.av{width:34px} td.av a{width:30px;height:30px} }
/* The class list on a phone: the face beside the name, not on a row of its own,
   and no NAME label - a row is obviously a person.
   James, 2026-10-01: "On mobile it could be arranged to use space better". */
@media (max-width:760px) and (orientation:portrait){
  table.dirlist tbody tr{display:grid;grid-template-columns:40px minmax(0,1fr);
                         column-gap:12px;align-items:start;padding:10px 16px}
  table.dirlist tbody td{padding:0;width:auto}
  table.dirlist tbody td::before{content:none}
  table.dirlist td.av{grid-row:1 / span 3;width:40px;padding-top:2px}
  table.dirlist td.av a{width:40px;height:40px}
  table.dirlist td[data-l]{grid-column:2}
  table.dirlist td[data-l="Where"]:empty,
  table.dirlist td[data-l="Occupation"]:empty{display:none}
  table.dirlist td[data-l="Where"],table.dirlist td[data-l="Occupation"],
  table.dirlist .ybp{font-size:15px;line-height:1.35;margin-top:0}
  /* WHERE and OCCUPATION kept, small and on the same line as the value; NAME is
     obvious and goes. James, 2026-10-01. */
  table.dirlist td[data-l="Where"]::before,
  table.dirlist td[data-l="Occupation"]::before{content:attr(data-l);display:inline;
    margin-right:6px;font-size:11px;font-weight:700;letter-spacing:.08em;
    text-transform:uppercase;color:var(--faint)}
}

/* "email hidden" on a guestbook entry: says we hold an address without being
   the address. The old guestbook published all 129 of them, which is why it
   filled with spam; this records that we have it and stops there. */
.entry .by .held{color:#9a9187;font-size:12px;font-style:italic;margin-left:2px}

/* editing somebody else's entry should never look like editing your own */
.adminedit{display:flex;gap:16px;align-items:center;justify-content:space-between;
  background:#fdf6e3;border:1px solid #e0d3a8;border-left:4px solid #c8a23a;
  border-radius:4px;padding:12px 16px}
.adminedit span{display:block;margin-top:3px;font-size:14px;color:#6b5c2c;max-width:70ch}

/* In Memory: a quiet list, name and date, nothing else competing for attention */
.memorial{list-style:none;margin:24px 0 0;padding:0;border-top:1px solid var(--line)}
/* Three real columns. space-between was fine with two items but pushed a third
   around depending on whether the row had an obituary, so the dates no longer
   lined up down the page. Fixed widths on the two right-hand columns, and the
   obituary span is rendered even when empty, so every row aligns. */
.memorial li{display:flex;align-items:baseline;gap:18px;
  padding:11px 2px;border-bottom:1px solid var(--line)}
.memorial .who{font-family:var(--serif,Georgia,serif);font-size:18px;
  flex:1 1 auto;min-width:0}
.memorial .who a{text-decoration:none;border-bottom:1px solid var(--line)}
.memorial .when{color:var(--dim);font-size:14px;white-space:nowrap;
  flex:0 0 150px;text-align:right}
.memorial .obit{font-size:14px;white-space:nowrap;flex:0 0 82px;text-align:right}
.memorial .obit .muted{font-size:13px;cursor:help}
@media (max-width:520px){
  .memorial li{flex-wrap:wrap;gap:2px 12px}
  .memorial .who{flex:1 0 100%}
  .memorial .when{flex:0 0 auto;text-align:left}
  .memorial .obit{flex:0 0 auto;text-align:left}
}

/* someone remembered, shown on their own entry and marked in the list */
.inmem{margin:6px 0 0;font-size:14px;color:#6b5c2c;background:#fdf6e3;
  border-left:3px solid #c8a23a;padding:7px 12px;border-radius:0 3px 3px 0;display:inline-block}
.inmem a{color:inherit}

/* hidden means hidden - for every element, whatever class it carries.
   The browser's own [hidden]{display:none} is the weakest rule on the page, so
   ANY class that sets display defeats it. It happened twice: the lightbox above
   (fixed for that one element with .lb[hidden]), and on 2026-09-17 the "who this
   reaches has changed" warning, which carries .hint{display:block} and so showed
   permanently - James: "this message is always shown". !important is the point:
   nothing on this site means hidden to be visible. */
[hidden]{display:none !important}

/* ---- the phone nav (base.html .mnav). James, 2026-09-18 ----
   Under 760px the full bar wrapped to three rows, a quarter of an iPhone
   screen. There the site name scrolls away and one 46px row stays frozen at
   the top: Class List, Guestbook, Photos, Your entry / Sign in, and a Menu for
   the rest. Wider than that nothing changes. */
.mnav{display:none}
/* The NAV breakpoint: 1100px (raised from 900, James 2026-09-27, so the full admin row always fits), not the 760px the page layout uses. Below that
   the full menu no longer fits on one line (eleven items for an admin), so
   the phone strip takes over. The same number is in two other places: the
   tier rule below and _reunion_banner.html. James, 2026-09-19. */
@media (max-width:1100px){
  .masthead .nav{display:none}
  .masthead .wrap{padding-top:9px;padding-bottom:9px}
  .masthead.yb .wrap{padding-top:12px;padding-bottom:12px}
  .masthead.yb{--seal:52px}
  .masthead.yb .brand span{font-size:18px;line-height:1.15}
  /* Two lines on a phone, so "50 Years" has room beside it (they overlapped). */
  .masthead.yb .brand span b{display:block}
  .masthead.yb .brand span i{display:none}
  /* The phone's menu strip is its own element (it stays pinned while you
     scroll), so it kept the old maroon until James asked, 2026-09-19: "Why cant
     the mobile be the same". It gets the same yearbook paper, continuing the
     header's picture at the same face size, with maroon words. */
  .masthead.yb{background-size:auto 155px;background-position:center top}
  .masthead.yb + .mnav{background-color:var(--ground);background-repeat:repeat-x;
        background-position:center bottom;background-size:auto 155px;
        border-top:0;
        box-shadow:0 1px 0 var(--line),0 2px 6px rgba(0,0,0,.10)}
  .masthead.yb + .mnav>a,.masthead.yb + .mnav summary{color:var(--maroon)}
  /* A real underline under the word: the old inset shadow sat at the bottom
     of the whole strip, well below the text (James, 2026-09-19). */
  .masthead.yb + .mnav>a.on,.masthead.yb + .mnav summary.on,
  .masthead.yb + .mnav .more[open] summary{color:var(--maroon);font-weight:800;box-shadow:none;
        text-decoration:underline 3px var(--red);text-underline-offset:6px}
  .masthead.yb + .mnav .panel{background:var(--ground);border:1px solid var(--line);border-top:0}
  .masthead.yb + .mnav .panel a{color:var(--maroon);border-bottom-color:var(--line)}
  .masthead.yb + .mnav .panel a.on{color:var(--maroon);font-weight:800}
  .masthead.yb + .mnav .panel a.adm{color:#9a6a00}
  /* 50 Years fits beside the name on a phone - the menu is not in that row. */
  .masthead.yb .fifty{display:block;top:50%;right:14px;font-size:30px}
  .brand img{width:30px}
  .brand span{font-size:17px}
  .mnav{display:flex;align-items:stretch;justify-content:space-between;
        position:sticky;top:0;z-index:59;background:var(--maroon); /* above the reunion banner (58), so the open Menu lies over it */
        border-top:1px solid rgba(255,255,255,.14);box-shadow:0 2px 6px rgba(0,0,0,.18);
        padding:0 8px;height:46px;font-size:15px;font-weight:600}
  .mnav>a,.mnav summary{display:flex;align-items:center;padding:0 7px;
        color:var(--ground);white-space:nowrap}
  .mnav>a:hover{text-decoration:none}
  .mnav>a.on,.mnav summary.on{color:var(--gold);box-shadow:inset 0 -3px 0 var(--gold)}
  .mnav .more summary{list-style:none;cursor:pointer;gap:6px;height:100%}
  .mnav .more summary::-webkit-details-marker{display:none}
  .mnav .more summary::after{content:"";width:16px;height:12px;
        background:linear-gradient(currentColor 0 0) 0 0/100% 2px no-repeat,
                   linear-gradient(currentColor 0 0) 0 50%/100% 2px no-repeat,
                   linear-gradient(currentColor 0 0) 0 100%/100% 2px no-repeat}
  .mnav .more[open] summary{color:var(--gold)}
  /* One narrow column under Menu, not a full-width sheet. James, 2026-09-18. */
  .mnav .panel{position:absolute;right:0;top:46px;min-width:170px;background:var(--maroon);
        display:flex;flex-direction:column;padding:2px 0 6px;border-radius:0 0 0 6px;
        box-shadow:0 10px 20px rgba(0,0,0,.28)}
  .mnav .panel a{color:var(--ground);padding:9px 18px;font-size:15px;line-height:1.3;
        border-bottom:1px solid rgba(255,255,255,.1)}
  .mnav .panel a:last-child{border-bottom:0}
  .mnav .panel a.on,.mnav .panel a.adm{color:var(--gold)}
  /* Two things that would otherwise sit under the frozen row: anything
     jumped to by #id (the admin claims page links to #c<id>), and the
     guestbook's own sticky search bar, which stacks below it. The dev-copy
     banner stops being sticky here, or the two would fight for the top. */
  [id]{scroll-margin-top:56px}
  .gbbar{top:46px}
  .devbar{top:46px}
  body:has(.devbar) .gbbar{top:84px}
}
/* Phone nav tiers (base.html phone_menu). Tier 2 lives in the Menu on a
   narrow phone and moves into the strip once there is room - a phone turned to
   landscape. Nothing else about the strip changes. */
.mnav>a.t2{display:none}
@media (min-width:560px) and (max-width:1100px){
  .mnav>a.t2{display:flex}
  .mnav>a,.mnav summary{padding:0 5px}   /* nine items and the house, 2026-09-25 */
  .mnav .panel a.t2{display:none}
  .mnav summary.on-t2,.masthead.yb + .mnav summary.on-t2{color:inherit;box-shadow:none;
        font-weight:inherit;text-decoration:none}
  .masthead.yb + .mnav summary.on-t2{color:var(--maroon)}
}
/* 430, was 360: the house and Reunion joined the strip (2026-09-25) and a
   390px phone pushed the Menu off the edge. */
@media (max-width:430px){
  .mnav{font-size:14px;padding:0 4px}
  .mnav>a,.mnav summary{padding:0 5px}
  .mnav>a.home{padding:0 3px}
}

/* The admin home's tool buttons, in three labelled groups (admin.html).
   Wrapping keeps the buttons in step: no per-button margins. */
.admintools{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px 26px;margin:22px 0 4px}
.admintools h3{flex:0 0 100%;margin:0 0 2px;font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.admintools .grp{display:flex;flex-wrap:wrap;gap:8px;align-content:flex-start}
.admintools .btn{width:auto;padding:9px 16px;font-size:15px;min-height:40px}

/* The admin's "Waiting for you" bar and the viewing-as bar. 2026-09-19. */
/* Fixed to the BOTTOM of the window, not the top. The top already has a stack
   that pins itself in a known order - the menu row, the reunion ticker, the
   guestbook search bar - and this sits above all of them in the page, so
   sticking it at the top would cover the menu. The bottom is empty, it is in
   view on every page and every scroll position, and it is where the eye goes
   on a phone. James, 2026-09-19: "can you make it sticky?" */
.attnbar{position:fixed;left:0;right:0;bottom:0;z-index:66;
  background:#fff3cf;border-top:1px solid #e2c46a;font-size:15px;line-height:1.5;padding:8px 0;
  box-shadow:0 -2px 10px rgba(0,0,0,.14)}
/* So the last of the footer is never underneath it. */
body:has(.attnbar) footer.site{padding-bottom:56px}
/* The View-as pill lives in the same corner: lift it clear. */
body:has(.attnbar) .adminpill{bottom:56px}
.attnbar .lbl{font-weight:700;letter-spacing:.06em;text-transform:uppercase;font-size:12px;margin-right:10px;color:#6b5314}
.attnbar a{color:#5a4300;text-decoration:underline}
.attnbar a.red{color:#fff;background:#8a1c1c;text-decoration:none;font-weight:700;padding:2px 8px;border-radius:3px}
.attnbar .sep{margin:0 8px;color:#b39545}
.attnbar a.quiet{color:#8a7440;text-decoration:none;font-size:13px}
.viewingbar{position:sticky;top:0;z-index:70;margin:0;display:flex;gap:14px;align-items:center;
  justify-content:center;flex-wrap:wrap;background:#1f3b5c;color:#fff;padding:8px 16px;font-size:15px}
.viewingbar button{cursor:pointer;border:1px solid #fff;background:#fff;color:#1f3b5c;
  font-weight:700;border-radius:3px;padding:3px 12px}
.addr .rm{font-weight:400;font-size:14px;color:#6b6357;margin-left:12px;cursor:pointer;display:inline}

/* Column headings you click to sort (Visits, In Memory). 2026-09-27. */
.sorth{font:inherit;font-weight:700;color:inherit;background:none;border:0;padding:0;cursor:pointer}
.sorth::after{content:" \2195";opacity:.35;font-weight:400}
.sorth[aria-sort=ascending]::after{content:" \25B2";opacity:.7;font-size:.75em}
.sorth[aria-sort=descending]::after{content:" \25BC";opacity:.7;font-size:.75em}
.memorial .mhead{display:flex;align-items:baseline;gap:18px;padding:8px 2px;
  font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);
  border-bottom:1px solid var(--line)}
.memorial .mhead .who{font-family:inherit;font-size:inherit}
.memorial ul{list-style:none;margin:0;padding:0}
@media (max-width:520px){
  .memorial .mhead .when{flex:0 0 auto;text-align:left}
  .memorial .mhead .who{flex:0 0 auto}
}

/* Reconnected: the `found` tag as visitors see it - a small badge WITH a thin gold
   ring round the picture (colour alone is missed, and means nothing to anyone who
   cannot tell the colours apart). The word is in _rc.html. James and his wife,
   2026-09-28. */
:root{--rc:#c9962a}
tr.rc td.av a{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--rc);
  /* above the next cell: on a shaded row its background painted over the right
     edge of the ring. James, 2026-10-01: "the gold outline is being cropped" */
  position:relative;z-index:1}
.thennow.rc img,.thennow.rc .noface{box-shadow:0 0 0 3px #fff,0 0 0 7px var(--rc)}
.thennow.rc figcaption{margin-top:14px}   /* clear of the ring */
.rcbadge{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:9px;font:700 11px/1.6 inherit;
  letter-spacing:.06em;text-transform:uppercase;background:#f7eed6;color:#7a5a12;
  border:1px solid #e6d29c;vertical-align:1px;font-style:normal}
.viewpick .vpsep{margin:0 10px;color:var(--faint)}

/* Class list: the view switch, and every name in columns (2026-10-01) */
.viewpick{margin:14px 0 0;font-size:15px}
.namecols{list-style:none;margin:14px 0 0;padding:0;columns:15em;column-gap:28px}
.namecols li{break-inside:avoid;padding:3px 0;font-size:15px}
.namecols a.died{color:var(--faint)}
