/* CEATL — College of Engineering and Architecture brand theme.
   Offline kiosk: no CDNs, no network fonts.

   Palette (supplied by CEA):
     #d7251b  primary + primary button        #114b9f  secondary + secondary button
     #000000  headers                         #fdfdfd  headers/body on colour
     #1d1d1d  body text

   Typography: Newsreader (serif headings) + Manrope (sans body). Both must be
   SELF-HOSTED — see the @font-face block below. Until the files are dropped in,
   the stacks fall back to Georgia and system-ui, which are metrically close.

   Screen: 15.6in 1080p kiosk. Chromium is launched with
   --force-device-scale-factor=1.5, so the CSS viewport is 1280x720 at an
   effective ~94 PPI. Do not design against 1920 CSS pixels.               */

/* Drop Newsreader*.woff2 and Manrope*.woff2 into static/fonts/ and uncomment.
@font-face{font-family:Newsreader;src:url("/static/fonts/Newsreader-Regular.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Newsreader;src:url("/static/fonts/Newsreader-Medium.woff2") format("woff2");
  font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Manrope;src:url("/static/fonts/Manrope-Regular.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Manrope;src:url("/static/fonts/Manrope-SemiBold.woff2") format("woff2");
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:Manrope;src:url("/static/fonts/Manrope-Bold.woff2") format("woff2");
  font-weight:700;font-style:normal;font-display:swap}
*/

:root{
  --paper:#f6f6f7; --card:#ffffff; --ink:#1d1d1d; --head:#000000; --muted:#6a6a6e;
  --red:#d7251b; --red-2:#b81d15; --red-soft:#fceae9;
  --blue:#114b9f; --blue-2:#0d3c80; --blue-soft:#e9eff9;
  --on-brand:#fdfdfd;
  --rule:#e5e5e8; --rule-strong:#d4d4d8; --rule-soft:#efeff1;
  --ok:#1b7a46; --ok-soft:#e9f4ee; --bad:#d7251b; --bad-soft:#fceae9;
  --warn:#a96b00; --warn-soft:#fbf1e1;
  --serif:Newsreader,Georgia,"Palatino Linotype","Times New Roman",serif;
  --sans:Manrope,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:"DejaVu Sans Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --wrap:1080px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);
  font-size:17px;line-height:1.55;display:flex;flex-direction:column;min-height:100vh;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--blue);text-decoration:none}
a:hover{color:var(--blue-2)}
h1,h2,h3{font-family:var(--serif);font-weight:500;line-height:1.18;letter-spacing:-.012em;color:var(--head)}

/* Header ------------------------------------------------------------ */
/* White brand band running to the top edge, with a red rule beneath. The CEA
   shield is mostly #ec202b, so it cannot sit on a red or blue field — it
   measures ~1.15:1 against #d7251b and the silhouette disappears. */
.site-head{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:.85rem clamp(1rem,3vw,2.5rem);border-bottom:5px solid var(--red);
  background:var(--on-brand);position:sticky;top:0;z-index:20;
}
.brand{display:flex;align-items:center;gap:.8rem}
.brand-logo{height:48px;width:auto;display:block;flex:0 0 auto}
.brand-text{display:flex;flex-direction:column;gap:.12rem;min-width:0}
.brand-mark{font-size:.85rem;font-weight:700;line-height:1.2;color:var(--red)}
.brand-sub{font-size:.6rem;letter-spacing:.11em;color:var(--head);text-transform:uppercase}
.site-nav{display:flex;gap:.5rem}
.site-nav a{
  min-height:48px;display:inline-flex;align-items:center;
  font-size:.88rem;font-weight:600;padding:0 1.15rem;border:1px solid var(--rule-strong);
  border-radius:4px;background:var(--card);color:var(--ink);
}
.site-nav a:hover,.site-nav a:focus{border-color:var(--blue);color:var(--blue)}
.site-nav a.is-on{background:var(--blue);border-color:var(--blue);color:var(--on-brand)}

.site-main{flex:1;width:100%;max-width:var(--wrap);margin:0 auto;padding:clamp(1rem,2.4vw,1.5rem) clamp(1rem,3vw,2.5rem)}

/* Footer ------------------------------------------------------------ */
.site-foot{
  border-top:1px solid var(--rule);background:var(--card);
  padding:.85rem clamp(1rem,3vw,2.5rem);
  display:flex;flex-wrap:wrap;gap:.4rem 1.2rem;align-items:center;
  font-size:.74rem;color:var(--muted);
}
.foot-note{flex:1;min-width:200px}
.foot-admin{font-size:.72rem;color:var(--muted);border-bottom:1px dotted var(--muted)}

/* Hero -------------------------------------------------------------- */
.eyebrow{font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;color:var(--red);font-weight:700;margin:0 0 .7rem}
/* Home hero: the layout is unchanged — full-width copy, search box and action
   tiles. The photo is a decorative layer pinned to the empty top-right, sitting
   BEHIND the content, so the search box and tiles always render over it.
   pointer-events:none keeps it from swallowing a tap on the kiosk. */
.hero{padding:.4rem 0 .6rem;position:relative}
.hero-copy{position:relative;z-index:1}
/*  Sized by HEIGHT so the whole photo shows and its base lands exactly on the
    top of the tile row: the hero's padding box runs to the bottom of that row,
    so subtracting the row (130px) and the hero's own bottom padding (.6rem)
    leaves precisely the space above it. Width follows the aspect ratio.
    It must not extend past that line — the 12.8px gaps between the tiles would
    let it show through. If the tile height changes, change it here too. */
.hero-photo{position:absolute;z-index:0;top:0;right:0;
  height:calc(100% - 130px - .6rem);width:auto;
  display:block;pointer-events:none;user-select:none;
  /*  Only the last stretch fades, so the figures are whole and just dissolve
      into the page where they meet the tiles. */
  -webkit-mask-image:linear-gradient(to bottom,#000 76%,transparent 99%);
  mask-image:linear-gradient(to bottom,#000 76%,transparent 99%)}
@media (max-width:1040px){
  /* Below this the lede runs into the photo, and it is only decoration. */
  .hero-photo{display:none}
}
.hero-title{font-size:clamp(1.9rem,4.2vw,2.45rem);margin:0 0 .75rem}
.hero-lede{font-size:1rem;max-width:66ch;color:var(--ink);margin:0 0 1.1rem}
/*  The field stops at the right edge of the middle tile. The row below is a
    3-column grid with a .8rem gap, so two columns plus one gap works out to
    (200% - gap) / 3 of the form's width — it stays aligned if the wrap width
    or the gap ever changes. */
.search-field{position:relative;width:calc((200% - .8rem) / 3)}
.hero-search textarea{
  width:100%;display:block;font-family:var(--serif);font-size:1.12rem;
  /*  Bottom padding clears the submit link sitting inside the box. */
  padding:.9rem 1.05rem 2.9rem;
  border:2px solid var(--ink);border-radius:4px;background:var(--card);
  /*  No drag handle: it would land on top of the submit link, and there is no
      mouse on the kiosk to use it with. */
  resize:none;color:var(--ink);
}
.hero-search textarea:focus{outline:none;border-color:var(--red);box-shadow:0 0 0 3px rgba(215,37,27,.14)}

/*  Text-only submit: no fill, red, underlined, arrow. It has to undo most of
    the base button rule. The padding is there for the fingertip — it makes the
    tap target ~44px tall without touching the underline, which follows the
    text only. */
.search-go{
  position:absolute;right:.75rem;bottom:.35rem;
  min-height:0;padding:.55rem .3rem;border:0;border-radius:0;background:transparent;
  color:var(--red);font-family:var(--sans);font-size:.92rem;font-weight:700;
  display:inline-flex;align-items:center;gap:.35rem;line-height:1.2;
}
.search-go span{text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1.5px}
.search-go:hover{background:transparent;color:var(--red-2)}
.search-go svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}

.hero-search .action-btn{margin-top:0}

/* Buttons — SOLID red = primary/affirmative, OUTLINED red = destructive,
   blue = secondary, grey outline = tertiary. Primary and destructive share a
   hue, so the fill is what separates them. Keep it that way. */
button,.btn{
  font-family:var(--sans);font-size:.94rem;font-weight:600;cursor:pointer;
  min-height:52px;padding:0 1.6rem;display:inline-flex;align-items:center;
  justify-content:center;gap:.45rem;
  border:1px solid var(--red);background:var(--red);color:var(--on-brand);border-radius:4px;
}
button:hover,.btn:hover{background:var(--red-2);border-color:var(--red-2);color:var(--on-brand)}
.btn{display:inline-flex}
.btn-primary{background:var(--red);border-color:var(--red);color:var(--on-brand)}
.btn-secondary{background:var(--blue);border-color:var(--blue);color:var(--on-brand)}
.btn-secondary:hover{background:var(--blue-2);border-color:var(--blue-2)}
.btn-ghost{background:var(--card);color:var(--blue);border-color:var(--blue)}
.btn-ghost:hover{background:var(--blue-soft);color:var(--blue-2);border-color:var(--blue)}
.btn-quiet{background:var(--card);color:var(--ink);border-color:var(--rule-strong)}
.btn-quiet:hover{background:var(--card);color:var(--ink);border-color:var(--muted)}
.btn-danger{background:var(--card);color:var(--red);border-color:#efc3bf}
.btn-danger:hover{background:var(--bad-soft);border-color:var(--red);color:var(--red)}
.ghost-link{color:var(--blue);font-weight:600;border-bottom:1px solid transparent}
.ghost-link:hover{border-color:var(--blue)}


/* Home actions ------------------------------------------------------ */
/* One uniform row: all three tiles share the same treatment, so the kiosk shows
   a single obvious band of things to press. */
.hero-actions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.8rem;margin-top:.9rem}
/*  Icon and label share the first row; the sub-line is pushed onto its own by
    flex-basis:100%. Wrapping does the work, so the markup is untouched. */
.action-btn{
  min-height:130px;display:flex;flex-flow:row wrap;align-items:center;
  align-content:center;justify-content:flex-start;gap:0;
  padding:.85rem 1.1rem;text-align:left;
  border:1px solid var(--blue);border-radius:4px;background:var(--card);color:var(--blue);
  font-family:var(--sans);cursor:pointer;
}
.action-btn:hover{background-color:var(--blue-soft);border-color:var(--blue);color:var(--blue)}
.action-ic{display:flex;flex:0 0 auto;margin-right:.45rem}
.action-ic svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round}
/*  One line, always. The widest label is "Search the archive" at ~170px; with
    the icon block at ~31px that needs ~201px of row, which is what the
    padding-right values below leave free. Shrink that padding, grow this font,
    or lengthen a label and it will overflow instead of wrapping. */
.action-label{flex:0 1 auto;min-width:0;font-size:1rem;font-weight:700;
  line-height:1.2;white-space:nowrap}
.action-sub{flex:0 0 100%;font-size:.8rem;font-weight:500;opacity:.85;
  line-height:1.3;margin-top:.3rem}
.action-btn[disabled]{opacity:.45;cursor:default}
.action-btn[disabled]:hover{background-color:var(--card);border-color:var(--blue)}

/*  Illustrated tiles. The artwork is decorative, so it is a background rather
    than an <img> — and the extra right padding is what keeps the label and
    sub-line clear of it as the tile flexes.

    Sized by WIDTH, not height: the illustrations have different aspect ratios,
    so matching their heights would leave them with visibly different footprints
    in the row. A shared width keeps the right margin identical and lets each
    one find its own height.

    Note the hover rules above use background-color, not the shorthand: the
    shorthand would blank these images every time a finger touched them.  */
.action-btn.has-illus{
  background-repeat:no-repeat;background-position:right .75rem center;
  background-size:108px auto;padding-right:7.9rem;
}
/*  Search is the one portrait piece (0.77:1). At the shared 108px width it
    would stand 140px tall and be clipped by the 130px tile, so this one is
    capped by HEIGHT instead and its padding-right follows the width that
    falls out of that (~74px).  */
.action-btn.is-search{
  background-image:url("/static/img/sort-illus.webp");
  background-size:auto 74%;padding-right:6rem;
}
.action-btn.is-recent{background-image:url("/static/img/bookshelf-illus.webp")}
.action-btn.is-popular{background-image:url("/static/img/search-illus.webp")}

/* Sheets (Recently added / Most consulted) --------------------------- */
/* <dialog> renders in the browser's top layer, so it sits above the idle
   overlay regardless of z-index — app.js closes any open sheet before the
   attract screen appears. */
dialog.sheet{
  border:0;padding:0;border-radius:6px;background:var(--card);color:var(--ink);
  width:min(1080px,calc(100vw - 2.5rem));max-height:calc(100vh - 2.5rem);
  box-shadow:0 18px 60px rgba(0,0,0,.28);overflow:hidden;
}
dialog.sheet[open]{display:flex;flex-direction:column}
dialog.sheet::backdrop{background:rgba(0,0,0,.5)}
.sheet-head{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;flex:0 0 auto;
  padding:1rem 1.3rem;background:var(--on-brand);border-bottom:4px solid var(--red);
}
.sheet-head-t{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.sheet-eyebrow{font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--red);font-weight:700}
.sheet-title{font-family:var(--serif);font-size:1.5rem;font-weight:500;color:var(--head);
  line-height:1.2;letter-spacing:-.012em}
/*  Close matches the header's Search / Ask CEATL buttons: neutral at rest,
    blue only while it is pressed or focused.  */
.sheet-close{flex:0 0 auto;min-height:48px;padding:0 1.4rem}
.sheet-close:hover,.sheet-close:focus,.sheet-close:focus-visible,.sheet-close:active{
  background:var(--card);border-color:var(--blue);color:var(--blue)}
.sheet-body:focus{outline:none}
.sheet-body{padding:1.2rem 1.3rem 1.4rem;overflow-y:auto;-webkit-overflow-scrolling:touch}

/* Shelves + cards --------------------------------------------------- */
.shelf{margin-top:2rem}
.shelf-title{font-size:1.25rem;margin:0 0 .9rem;padding-bottom:.5rem;border-bottom:1px solid var(--rule)}
.card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem}
.card{
  display:flex;flex-direction:column;background:var(--card);border:1px solid var(--rule);
  border-radius:4px;padding:0 0 .85rem;overflow:hidden;transition:border-color .12s,transform .12s;
}
.card:hover{border-color:var(--red);transform:translateY(-2px)}
.card-tab{
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin:0 0 .6rem;
  padding:.5rem .85rem;border-bottom:1px solid var(--rule-soft);background:#fafafb;
}
.call-no{font-family:var(--mono);font-size:.62rem;letter-spacing:.02em;color:var(--blue);font-weight:600}
.relevance{font-family:var(--mono);font-size:.62rem;color:var(--blue);font-weight:700;margin-left:auto}
.status{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;padding:.18rem .5rem;border-radius:2px}
.status-completed{background:var(--ok-soft);color:var(--ok)}
.status-ongoing{background:var(--warn-soft);color:var(--warn)}
.card-title,.card-authors,.card-abstract,.card-foot{padding:0 .85rem}
.card-title{font-size:1rem;margin:0 0 .3rem;line-height:1.3}
.card-authors{font-size:.75rem;color:var(--muted);margin:0 0 .45rem}
.card-abstract{font-size:.78rem;color:var(--ink);margin:0 0 .6rem;line-height:1.5}
.card-foot{display:flex;flex-wrap:wrap;gap:.45rem;align-items:center;font-size:.68rem;color:var(--muted);margin:auto 0 0}
.kw{background:var(--rule-soft);color:var(--ink);padding:.16rem .5rem;border-radius:2px;font-size:.7rem}

/* Search ------------------------------------------------------------ */
.search-head{margin-bottom:1.3rem}

/*  Prompt above the field. Same shape as the home hero — red eyebrow, serif
    headline, plain lede — so the two screens read as one product. */
.search-intro{margin:0 0 1.1rem}
.search-intro .eyebrow{margin-bottom:.5rem}
.search-intro-title{font-size:clamp(1.5rem,3vw,1.95rem);margin:0 0 .45rem}
.search-intro-lede{font-size:1rem;color:var(--ink);margin:0;max-width:60ch}
.search-bar textarea{
  width:100%;font-family:var(--serif);font-size:1.06rem;padding:.8rem 1rem;
  border:2px solid var(--ink);border-radius:4px;background:var(--card);resize:vertical;color:var(--ink);
}
.search-bar textarea:focus{outline:none;border-color:var(--red)}
.filters{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:.7rem}
.filters select,.filters input{
  font-family:var(--sans);font-size:.88rem;min-height:48px;padding:0 .75rem;
  border:1px solid var(--rule-strong);border-radius:4px;background:var(--card);color:var(--ink);
}
.filters input[name=year]{width:6.5rem}
/*  The archive search is a neutral retrieval action, not an affirmative
    one, so it takes the secondary blue rather than the primary red.  */
.filters button{padding:0 1.5rem;background:var(--blue);border-color:var(--blue);
  color:var(--on-brand)}
.filters button:hover{background:var(--blue-2);border-color:var(--blue-2);color:var(--on-brand)}
.result-count{font-family:var(--mono);font-size:.76rem;color:var(--muted);margin:0 0 1rem}

/* Record (detail) --------------------------------------------------- */
.record{background:var(--card);border:1px solid var(--rule);border-left:5px solid var(--red);border-radius:4px;padding:clamp(1.2rem,2.6vw,1.9rem)}
.record-callno{font-family:var(--mono);font-size:.72rem;font-weight:600;color:var(--red);display:flex;gap:.7rem;align-items:center;margin-bottom:.7rem}
.record-title{font-size:clamp(1.5rem,3.2vw,1.95rem);margin:0 0 .35rem}
.record-authors{color:var(--muted);margin:0 0 1.1rem;font-size:.88rem}
.record-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.8rem 1.4rem;margin:0 0 1.2rem;padding:1rem 0;border-top:1px solid var(--rule-soft);border-bottom:1px solid var(--rule-soft)}
.record-meta dt{font-size:.62rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);font-weight:700}
.record-meta dd{margin:.28rem 0 0;font-size:.88rem;color:var(--ink)}
.record-h{font-size:1.1rem;margin:1.25rem 0 .55rem}
.record-abstract{font-size:.97rem;line-height:1.7;color:var(--ink);text-align:justify}
.record-keywords{display:flex;flex-wrap:wrap;gap:.5rem;margin:1rem 0}
.record-citation{font-family:var(--mono);font-size:.76rem;color:var(--ink);background:var(--paper);padding:.8rem .9rem;border-radius:4px;line-height:1.55}
.access-note{margin-top:1.4rem;padding:.9rem 1.05rem;background:var(--blue-soft);border-left:3px solid var(--blue);border-radius:4px;font-size:.82rem;color:var(--blue-2);line-height:1.55}

/* Controlled full-text access */
.access-box{margin-top:1.4rem;padding:1.25rem 1.4rem;background:var(--bad-soft);border-left:4px solid var(--red);border-radius:4px}
.access-box .record-h{margin-top:0}
.access-form{display:flex;flex-wrap:wrap;gap:.7rem;margin:.85rem 0 .6rem}
.access-form input{flex:1;min-width:220px;font-size:.95rem;min-height:52px;padding:0 .9rem;border:1px solid var(--ink);border-radius:4px;background:var(--card);color:var(--ink)}
.access-form input:focus{outline:none;border-color:var(--red);box-shadow:0 0 0 3px rgba(215,37,27,.14)}
.privacy-note{font-size:.72rem;color:var(--muted);margin:.3rem 0 0;line-height:1.55}
.checkline{flex-direction:row;align-items:center;gap:.5rem;font-weight:400;font-size:.82rem;margin:.4rem 0}

/* Full-text reading view */
.reader{max-width:800px;margin:0 auto;background:var(--card);border:1px solid var(--rule);border-radius:4px;padding:clamp(1.2rem,3vw,2.2rem)}
.reader-bar{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding-bottom:.85rem;margin-bottom:1.25rem;border-bottom:1px solid var(--rule-soft)}
.reader-remaining{font-family:var(--mono);font-size:.72rem;color:var(--red);font-weight:600}
.reader-title{font-size:clamp(1.35rem,3vw,1.7rem);margin:0 0 .35rem}
.reader-authors{color:var(--muted);margin:0 0 1.4rem;font-size:.82rem}
.reader-body{font-family:var(--serif);font-size:1rem;line-height:1.78;color:var(--ink)}
.reader-body p{margin:0 0 1rem;text-align:justify}
.reader-foot{margin-top:1.6rem;padding-top:1rem;border-top:1px solid var(--rule-soft);font-size:.74rem;color:var(--muted);line-height:1.55}
.accesslog li span:first-child{overflow:hidden;text-overflow:ellipsis}
.back-row{margin-top:1.4rem}

/* Chat -------------------------------------------------------------- */
.chat{max-width:820px;margin:0 auto}
/* The intro is centred on the chat bar rather than ranged left, so the whole
   composition reads as one centred block. */
.chat-intro{text-align:center;margin-bottom:1.1rem}
.chat-intro h1{font-size:clamp(1.5rem,3.4vw,1.9rem);margin:.3rem 0 .5rem}
.chat-intro .hero-lede{max-width:56ch;margin-left:auto;margin-right:auto}
.chat-log{margin:1.3rem 0;display:flex;flex-direction:column;gap:.85rem;min-height:80px}
/* Before the first question the log is empty, and its reserved height was
   pushing the intro well clear of the bar. Collapse it until there is a reply. */
.chat-log:empty{min-height:0;margin:0}
.bubble{padding:.85rem 1.05rem;border-radius:4px;max-width:78%;font-size:.92rem;line-height:1.55}
.bubble.user{align-self:flex-end;background:var(--blue);color:var(--on-brand)}
.bubble.bot{align-self:flex-start;background:var(--card);border:1px solid var(--rule);border-left:3px solid var(--red);color:var(--ink)}
.bubble.bot .sources{margin-top:.65rem;padding-top:.6rem;border-top:1px dashed var(--rule);font-size:.76rem;display:flex;flex-wrap:wrap;gap:.4rem}
.bubble.bot .sources a{color:var(--blue);font-weight:600;background:var(--blue-soft);padding:.2rem .55rem;border-radius:2px;display:inline-block}
.bubble.thinking{color:var(--muted);font-style:italic}
.chat-form{display:flex;gap:.6rem}
.chat-form input{flex:1;font-size:.95rem;min-height:52px;padding:0 1rem;border:1px solid var(--ink);border-radius:4px;background:var(--card);color:var(--ink)}
.chat-form input:focus{outline:none;border-color:var(--red);box-shadow:0 0 0 3px rgba(215,37,27,.14)}
/*  Ask takes the secondary blue, matching the archive search button.
    chat.js disables it while the model is thinking, so it needs a visible
    waiting state — otherwise a student taps it again and again.  */
.chat-form button{background:var(--blue);border-color:var(--blue);color:var(--on-brand)}
.chat-form button:hover{background:var(--blue-2);border-color:var(--blue-2);color:var(--on-brand)}
.chat-form button:disabled{opacity:.55;cursor:default}
.chat-form button:disabled:hover{background:var(--blue);border-color:var(--blue)}
.chat-hint{font-size:.74rem;color:var(--muted);margin-top:.7rem;text-align:center}

/* Notices ----------------------------------------------------------- */
.notice{padding:.75rem 1rem;border-radius:4px;margin:.6rem 0;font-size:.84rem;line-height:1.55;border-left:3px solid}
.notice-error{background:var(--bad-soft);border-color:var(--bad);color:#9e1a12}
.notice-warn{background:var(--warn-soft);border-color:var(--warn);color:#7a4e00}
.notice-ok{background:var(--ok-soft);border-color:var(--ok);color:#145c36}
.notice code{font-family:var(--mono);font-size:.78rem;background:rgba(0,0,0,.05);padding:.05rem .25rem;border-radius:2px}
.empty{text-align:center;padding:2.6rem 1rem;color:var(--muted);background:var(--card);border:1px solid var(--rule);border-radius:4px}
.empty h2{color:var(--head);margin:0 0 .5rem}

/*  The hand-off to the assistant, under the field on the empty search screen. */
.empty.assist{padding:2rem 1.4rem 2.1rem}
.empty.assist p{max-width:56ch;margin:0 auto 1.3rem;color:var(--ink)}
.assist-cta{text-decoration:none}
.assist-cta svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round}

/* Idle / attract overlay -------------------------------------------- */
/* Shown by app.js after IDLE_RESET_SECONDS on the home screen. Markup lives in
   base.html; no extra route. */
.idle-screen{
  position:fixed;inset:0;z-index:100;background:var(--red);
  display:none;align-items:center;justify-content:center;padding:2rem;
}
.idle-screen.is-on{display:flex}
.idle-card{
  background:var(--on-brand);border-radius:6px;padding:2.2rem 3.2rem 2rem;
  max-width:820px;width:100%;text-align:center;box-shadow:0 8px 32px rgba(0,0,0,.18);
}
.idle-logo{height:104px;width:auto;display:block;margin:0 auto 1.1rem}
.idle-name{font-size:1rem;font-weight:700;color:var(--red);line-height:1.3;margin:0 0 .2rem}
.idle-sub{font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:var(--head);margin:0}
.idle-title{font-size:2.2rem;margin:1.15rem 0 .65rem}
.idle-lede{font-size:1rem;color:var(--ink);max-width:56ch;margin:0 auto 1.4rem}
.idle-cta{min-height:58px;font-size:1rem;padding:0 2.4rem}
.idle-foot{margin:1.3rem 0 0;padding-top:1.1rem;border-top:1px solid var(--rule);font-family:var(--mono);font-size:.7rem;color:var(--muted)}

/* Login ------------------------------------------------------------- */
.login{max-width:420px;margin:2rem auto;background:var(--card);border:1px solid var(--rule);border-radius:4px;padding:2rem}
.login-title{font-size:1.6rem;margin:0 0 .4rem}
.login-sub{color:var(--muted);margin:0 0 1.4rem;font-size:.85rem;line-height:1.55}
.login-form,.form{display:flex;flex-direction:column;gap:1rem}
label{display:flex;flex-direction:column;gap:.35rem;font-size:.68rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#4a4a4e}
input,textarea,select{font-family:var(--sans);font-size:.95rem;color:var(--ink)}
.login-form input,.form input,.form textarea,.form select{
  font-weight:400;text-transform:none;letter-spacing:0;padding:.6rem .75rem;
  border:1px solid var(--rule-strong);border-radius:4px;background:var(--card);
}
.form input:focus,.form textarea:focus,.form select:focus,.login-form input:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(17,75,159,.12)}

/* Admin ------------------------------------------------------------- */
.admin-body{background:var(--paper)}
.admin-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:1rem;margin-bottom:1rem}
.admin-head h1{font-size:1.6rem;margin:0}
.admin-actions{display:flex;gap:.6rem;align-items:center}
.admin-actions form{margin:0}
.admin-h{font-size:1.15rem;margin:1.8rem 0 .9rem;padding-bottom:.45rem;border-bottom:1px solid var(--rule)}
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.85rem}
.stat{background:var(--card);border:1px solid var(--rule);border-radius:4px;padding:.9rem 1rem;display:flex;flex-direction:column;gap:.15rem}
.stat-num{display:block;font-family:var(--serif);font-size:1.75rem;line-height:1.05;color:var(--head);font-weight:500}
.stat-lab{font-size:.62rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);font-weight:700}
.admin-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1rem;margin-top:1rem}
.panel{background:var(--card);border:1px solid var(--rule);border-radius:4px;padding:1.1rem 1.2rem}
.panel h3{font-size:.95rem;margin:0 0 .8rem}
.health,.toplist{list-style:none;margin:0;padding:0;font-size:.82rem}
.health li,.toplist li{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.5rem 0;border-bottom:1px solid var(--rule-soft)}
.health li:last-child,.toplist li:last-child{border-bottom:none}
.health b,.toplist b{color:var(--ink);font-weight:600}
.health b.ok{color:var(--ok)}
.health b.bad{color:var(--bad);font-weight:700}
.toplist li span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.muted{color:var(--muted)}
.pdf-helper{margin-bottom:1.4rem}
.pdf-helper input[type=file]{display:block;margin:.6rem 0;font-size:.85rem}
.form-row{display:grid;grid-template-columns:2fr 1fr 1fr;gap:1rem}
.form-actions{display:flex;flex-wrap:wrap;gap:.7rem;align-items:center;margin-top:.5rem}

/* Table ------------------------------------------------------------- */
.tbl{width:100%;border-collapse:collapse;background:var(--card);font-size:.82rem;
  border:1px solid var(--rule);border-radius:4px}
.tbl th,.tbl td{text-align:left;padding:.7rem .75rem;border-bottom:1px solid var(--rule-soft)}
.tbl th{font-size:.6rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);font-weight:700;border-bottom:1px solid var(--rule-strong)}
.tbl tr:last-child td{border-bottom:none}
.tbl .mono{font-family:var(--mono);color:var(--blue)}
.cell-title{font-family:var(--serif);font-size:.92rem;color:var(--head);max-width:340px;line-height:1.35}
.row-actions{white-space:nowrap;vertical-align:middle}
.row-actions a{margin-right:.9rem}
.row-actions form{margin:0}
.row-actions a{color:var(--blue);font-weight:600;border-bottom:1px solid transparent}
.row-actions a:hover{border-color:var(--blue)}
/* Destructive stays OUTLINED / text-only — solid red is reserved for primary. */
.link-danger{background:none;border:none;color:var(--bad);padding:0;font-size:.82rem;
  font-weight:600;text-decoration:underline;cursor:pointer;min-height:0}
.link-danger:hover{background:none;color:var(--red-2)}

/* Librarian dashboard shell ----------------------------------------- */
/* The sidebar carries the brand on admin pages, so base.html omits the public
   header, the 1080px wrap and the public footer there. */
.admin-app,.kiosk-app{display:flex;flex:1;min-height:0;align-items:stretch}
.admin-side,.kiosk-side{
  width:280px;flex:0 0 280px;background:var(--red);color:var(--on-brand);
  display:flex;flex-direction:column;padding:0 0 1.1rem;
}
/* White brand band to the top edge; red below it. The CEA shield cannot sit on
   a coloured field — see design/README.md. */
.admin-side-brand,.kiosk-side-brand{background:var(--on-brand);padding:1.15rem 1.15rem;
  display:flex;align-items:center;gap:.75rem}
.admin-side-brand img,.kiosk-side-brand img{height:52px;width:auto;display:block;flex:0 0 auto}
.admin-side-brand-t,.kiosk-side-brand-t{display:flex;flex-direction:column;gap:.16rem;min-width:0}
.admin-side-mark,.kiosk-side-mark{font-size:.78rem;font-weight:700;line-height:1.25;color:var(--red)}
.admin-side-sub,.kiosk-side-sub{font-size:.58rem;letter-spacing:.11em;text-transform:uppercase;color:var(--head)}
.admin-side-nav,.kiosk-side-nav{display:flex;flex-direction:column;gap:.12rem;padding:1.2rem .7rem 1rem}
.admin-side-nav form,.kiosk-side-nav form{margin:0}
.admin-side-lab,.kiosk-side-lab{font-size:.58rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-brand);opacity:.92;font-weight:700;padding:.4rem .5rem}
.admin-nav-item,.kiosk-nav-item{
  display:flex;align-items:center;gap:.6rem;width:100%;min-height:44px;
  padding:.55rem .6rem;border-radius:4px;border:0;border-left:3px solid transparent;
  background:none;font-family:var(--sans);font-size:.82rem;font-weight:500;
  color:var(--on-brand);text-align:left;cursor:pointer;justify-content:flex-start;
}
.admin-nav-item svg,.kiosk-nav-item svg{width:16px;height:16px;flex:0 0 16px;fill:none;stroke:currentColor;
  stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;opacity:.85}
.admin-nav-item:hover,.kiosk-nav-item:hover{background:rgba(253,253,253,.12);color:var(--on-brand)}
.admin-nav-item.is-active,.kiosk-nav-item.is-active{background:#b01a11;border-left-color:var(--on-brand);
  color:var(--on-brand);font-weight:600}
.admin-nav-item.is-active svg,.kiosk-nav-item.is-active svg{opacity:1}
.admin-side-foot,.kiosk-side-foot{margin-top:auto;padding:.9rem 1.15rem 0;
  border-top:1px solid rgba(253,253,253,.24);display:flex;flex-direction:column;gap:.15rem}
.admin-side-who,.kiosk-side-who{font-size:.76rem;font-weight:600;color:var(--on-brand)}
.admin-side-role,.kiosk-side-role{font-size:.68rem;color:var(--on-brand);opacity:.92}

.admin-main,.kiosk-main{flex:1;min-width:0;display:flex;flex-direction:column;background:var(--paper)}
.admin-topbar{
  display:flex;align-items:center;justify-content:space-between;gap:1.4rem;
  padding:1rem 1.9rem;background:var(--card);border-bottom:1px solid var(--rule);
}
.admin-topbar-l{display:flex;flex-direction:column;gap:.1rem}
.admin-topbar-l h1{font-size:1.4rem;margin:0}
.admin-topbar-r{display:flex;align-items:center;gap:.7rem}
.crumb{font-size:.62rem;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted);font-weight:700}
.admin-content{padding:1.5rem 1.9rem 2.4rem;display:flex;flex-direction:column;gap:1.1rem}
.admin-content .admin-cols{margin-top:0;grid-template-columns:repeat(auto-fit,minmax(420px,1fr))}

/* Student main column ------------------------------------------------ */
/* The shell is locked to the viewport and only the content pane scrolls, so the
   sidebar and the footer (with the Librarian link) are always on screen. Left to
   scroll as one page, a long thesis record pushes both out of reach — the
   navigation disappears exactly when a student is deepest into the interface. */
/* body is min-height:100vh and the shell is flex:1, so the shell grows with its
   content unless the body itself is pinned to the viewport. */
body.kiosk-body{height:100vh;min-height:100vh;overflow:hidden}
.kiosk-app{min-height:0;overflow:hidden}
.kiosk-side{overflow-y:auto}
.kiosk-main{min-height:0}
.kiosk-content{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
  display:flex;flex-direction:column}
/* `margin:auto` centres the column vertically while there is spare room — which
   is most of the time on a short page like an empty search — and collapses to
   zero the moment the content is taller than the pane, so long pages still start
   at the top and scroll normally. justify-content:center would clip the top of
   an overflowing pane instead. */
.kiosk-inner{width:100%;max-width:1000px;margin:auto;
  padding:1.5rem clamp(1rem,2.4vw,1.9rem) 1.8rem}
.kiosk-main > .site-foot{flex:0 0 auto}
.kiosk-side-brand{text-decoration:none}
.kiosk-side-foot .kiosk-side-who{font-size:.7rem;line-height:1.3}
.kiosk-side-foot .kiosk-side-role{font-size:.66rem;line-height:1.35}

/* Collection filters + table panel */
.filter-bar{display:flex;flex-wrap:wrap;gap:.6rem;align-items:center;padding:.8rem .9rem}
.filter-bar .filter-input{flex:1;min-width:240px}
.filter-bar input,.filter-bar select{
  font-family:var(--sans);font-size:.84rem;min-height:44px;padding:0 .7rem;
  border:1px solid var(--rule-strong);border-radius:4px;background:var(--card);color:var(--ink);
}
.filter-bar input:focus,.filter-bar select:focus{outline:none;border-color:var(--blue)}
.table-panel{padding:1.1rem 1.2rem .6rem}
.table-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:1rem;margin-bottom:.8rem}
.table-head h3{margin:0}
.table-head .muted{font-size:.72rem}
.table-panel .tbl{border:0}
.flag-yes{color:var(--ok);font-weight:700}
.flag-no{color:#b9b9bd}
.no-matches{padding:1.6rem 0;text-align:center;font-size:.84rem}

/* Delete confirmation dialog (replaces window.confirm) */
dialog.confirm{
  border:0;border-radius:6px;padding:1.5rem 1.6rem;max-width:460px;width:calc(100% - 2rem);
  box-shadow:0 12px 40px rgba(0,0,0,.24);color:var(--ink);font-family:var(--sans);
}
dialog.confirm::backdrop{background:rgba(0,0,0,.45)}
dialog.confirm h3{font-size:1.15rem;margin:0 0 .5rem}
.confirm-what{font-family:var(--serif);font-size:1rem;color:var(--head);
  margin:0 0 .6rem;line-height:1.35}
.confirm-note{font-size:.8rem;color:var(--muted);line-height:1.55;margin:0 0 1.1rem}
.confirm-actions{display:flex;gap:.7rem;justify-content:flex-end}
.confirm-actions form{margin:0}

/* Accessibility / motion / mobile ----------------------------------- */
:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* Touchscreen kiosk ------------------------------------------------- */
html{overscroll-behavior:none}                 /* kill pull-to-refresh & bounce */
body{
  -webkit-tap-highlight-color:transparent;     /* no grey flash on tap */
  -webkit-touch-callout:none;                  /* no long-press save/share menu */
  touch-action:manipulation;                   /* remove double-tap zoom + 300ms delay */
}
/* Don't let stray taps select UI text on public pages, but keep anything the
   user actually types or reads fully selectable. */
body:not(.admin-body){user-select:none;-webkit-user-select:none}
input,textarea,select,.reader-body,.record-abstract{user-select:text;-webkit-user-select:text}
/* Larger hit areas on touch screens (finger-friendly). At the kiosk's 1.5
   device scale factor, 48px is ~12.9mm physical — comfortably over the ~9mm
   minimum. At 1:1 on this panel it would be only 8.6mm. */
@media (pointer:coarse){
  button,.btn,.site-nav a,.filters select,.filters input,.row-actions a,.link-danger{
    min-height:48px;display:inline-flex;align-items:center;justify-content:center;
  }
  .link-danger{min-height:48px}
  /*  "← Back to search" / "← Back to record" / "Ask CEATL →". Text links, but
      on the kiosk they are the way back out of a record, and at 1920 they
      measured only 5.8mm tall — well under the ~9mm a fingertip needs. The
      padding grows the hit area, not the type. Excludes .foot-admin, which is
      deliberately discreet, staff-only, and would make the footer taller than
      the home screen's exact 720px fit allows. */
  .ghost-link{min-height:48px;display:inline-flex;align-items:center}
  .card{padding-bottom:1.1rem}
  input,textarea,select{font-size:1rem}      /* >=16px stops iOS/Android auto-zoom */
}

@media (max-width:640px){
  body{font-size:16px}
  .site-nav a{padding:0 .8rem}
  .form-row{grid-template-columns:1fr}
  .row-actions{flex-direction:column;gap:.3rem;align-items:flex-start}
  .brand-logo{height:38px}
  .idle-card{padding:1.6rem 1.4rem}
  .idle-title{font-size:1.6rem}
}

/* Kiosk scaling safety net ------------------------------------------- */
/*  The whole UI is designed against a 1280x720 CSS viewport, which the kiosk
    is supposed to get from Chromium's --force-device-scale-factor=1.5 on its
    1920x1080 panel (see deploy/kiosk-autostart.sh). If the browser is launched
    without that flag — by hand, by a desktop shortcut, by an autostart entry
    that does not go through the script — the page renders 1:1 and everything
    is a third too small: a 48px target measures 8.6mm instead of 13mm.

    This rule makes the design independent of how the browser was started. It
    only fires when the viewport is WIDER than the design, i.e. exactly when the
    scale factor is missing. With the flag applied the viewport is 1280 and this
    block never matches, so the two can never compound.

    `zoom` is used rather than a font-size scale because the layout carries real
    px constants (tile heights, illustration widths, the sidebar) that a rem
    scale would leave behind. Viewport units are NOT scaled by zoom, so every
    vh/vw length has to be divided by the same factor below — that is the whole
    catch of this technique. Add a new vh/vw length anywhere and correct it
    here too.  */
/*  1800px, not 1400 or 1600: a 1680x1050 or 1600x900 desktop must NOT be
    scaled — only a panel genuinely running 1920 wide at 1:1.  */
@media (min-width:1800px){
  :root{zoom:1.5}

  body{min-height:calc(100vh / 1.5)}
  body.kiosk-body{height:calc(100vh / 1.5);min-height:calc(100vh / 1.5)}

  dialog.sheet{
    width:min(1080px,calc((100vw / 1.5) - 2.5rem));
    max-height:calc((100vh / 1.5) - 2.5rem);
  }
}

/* ===========================================================================
   CEATL reading view + embedded PDF viewer
   =========================================================================== */
.read-body{ overflow:hidden; }
.reader{ display:flex; flex-direction:column; height:100vh; padding:14px 20px 18px; }
.reader-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:1rem; }
.reader-callno{ font-family:ui-monospace,"Courier New",monospace; font-size:.72rem;
  letter-spacing:.05em; color:var(--maroon,#7a1f2b); margin:0 0 2px; }
.reader-title{ font-size:1.15rem; color:var(--ink,#2b2019); margin:0; line-height:1.25; }
.reader-sub{ font-size:.85rem; color:var(--ink-soft,#6b5d4f); margin:2px 0 0; }
.reader-note{ font-size:.8rem; color:var(--ink-soft,#6b5d4f); margin:.5rem 0; }
.pdf-frame{ flex:1; min-height:0; border:1px solid var(--rule,#cbb9a3); border-radius:3px; overflow:hidden; }

/* PDF.js viewer */
.pdfv{ display:flex; flex-direction:column; height:100%; min-height:0;
  background:#3a3f44; border-radius:3px; overflow:hidden; }
.pdfv-toolbar{ display:flex; align-items:center; gap:.4rem; padding:.35rem .5rem;
  background:#2b2f33; color:#eee; font-family:var(--serif,Georgia,serif); }
.pdfv-btn{ font-family:inherit; font-size:.9rem; background:#4a4f55; color:#fff;
  border:1px solid #5c6570; border-radius:3px; padding:.22rem .7rem; cursor:pointer; }
.pdfv-btn:active{ transform:translateY(1px); }
.pdfv-page{ margin-left:auto; font-size:.85rem; color:#cfd2d6; letter-spacing:.03em; }
.pdfv-scroll{ flex:1; min-height:0; overflow:auto; padding:14px;
  display:flex; flex-direction:column; align-items:center; gap:14px; }
.pdfv-pageholder{ background:#fff; box-shadow:0 2px 10px rgba(0,0,0,.45); }
.pdfv-error{ color:#eee; padding:2rem; font-family:var(--serif,Georgia,serif); }

/* ===========================================================================
   Phones & small screens. The kiosk itself renders at 1280 CSS px and never
   trips these; they make the site usable when opened on a phone.
   =========================================================================== */
@media (max-width:768px){
  /* Let the whole page scroll naturally instead of the kiosk's locked viewport. */
  body.kiosk-body{ height:auto; min-height:100vh; overflow:visible; }
  .kiosk-app{ flex-direction:column; overflow:visible; min-height:0; align-items:stretch; }

  /* Sidebar becomes a compact top bar: brand, then a horizontal scrolling nav. */
  .kiosk-side{ width:auto; flex:0 0 auto; flex-direction:column; }
  .kiosk-side-brand{ padding:.7rem 1rem; }
  .kiosk-side-nav{ flex-direction:row; flex-wrap:nowrap; overflow-x:auto; gap:.3rem;
    padding:.5rem .6rem; -webkit-overflow-scrolling:touch; }
  .kiosk-side-lab{ display:none; }
  .kiosk-nav-item{ white-space:nowrap; min-height:42px; border-left:0;
    border-bottom:3px solid transparent; padding:.5rem .7rem; }
  .kiosk-nav-item.is-active{ border-left:0; border-bottom-color:var(--on-brand); }
  .kiosk-side-foot{ display:none; }

  .kiosk-main{ min-height:0; }
  .kiosk-content{ overflow:visible; min-height:0; display:block; }
  .kiosk-inner{ margin:0; max-width:none; padding:1rem; }

  /* Home: stack the hero tiles and let the search field fill the width. */
  .hero-actions{ grid-template-columns:1fr; }
  .search-field{ width:100%; }
  .hero-search textarea{ font-size:1rem; }

  /* Results / shelves: one card per row (no 300px min-track overflow). */
  .card-grid{ grid-template-columns:1fr; }

  /* Public header (home / login) wraps tidily. */
  .site-head{ flex-wrap:wrap; gap:.6rem; }
  .site-main{ padding:1rem; }

  /* Admin tables scroll sideways instead of overflowing the screen. */
  .table-panel, .admin-content{ overflow-x:auto; }
  .tbl{ min-width:620px; }
  .admin-app{ flex-direction:column; }
  .admin-side{ width:auto; flex:0 0 auto; }
  .admin-content{ padding:1rem; }
}

/* Extra squeeze for very narrow phones. */
@media (max-width:380px){
  .record-meta{ grid-template-columns:1fr; }
  .filters select, .filters input, .filters button{ width:100%; }
}

/* ===================================================================== *
 *  Admin — survey feedback view (/admin/surveys)                        *
 *  Inline-SVG charts + tables; no external chart library (offline).     *
 * ===================================================================== */
.stat-row{ display:flex; gap:1rem; flex-wrap:wrap; margin-bottom:1.1rem; }
.stat{ flex:1 1 180px; background:var(--card); border:1px solid var(--rule);
  border-radius:10px; padding:1rem 1.2rem; display:flex; flex-direction:column; gap:.2rem; }
.stat-n{ font-family:var(--mono); font-size:2rem; font-weight:700; color:var(--blue-2); line-height:1; }
.stat-l{ font-size:.78rem; color:var(--muted); }

.chart-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:1rem; margin-bottom:1.1rem; }
.chart-card h3{ margin:0 0 .15rem; font-size:1rem; color:var(--head); }
.chart-sub{ font-size:.76rem; margin:0 0 .7rem; }
.chart-body{ display:flex; align-items:center; gap:1rem; flex-wrap:wrap; }
.chart-pie{ flex:0 0 auto; }
.chart-pie .pie{ width:122px; height:122px; display:block; }
.chart-legend{ list-style:none; margin:0; padding:0; flex:1 1 140px;
  display:flex; flex-direction:column; gap:.3rem; min-width:0; }
.chart-legend li{ display:flex; align-items:center; gap:.45rem; font-size:.8rem; color:var(--ink); }
.chart-legend .sw{ flex:0 0 auto; width:.8rem; height:.8rem; border-radius:3px; }
.chart-legend .lg-label{ flex:1 1 auto; min-width:0; }
.chart-legend .lg-val{ flex:0 0 auto; font-family:var(--mono); font-size:.74rem; color:var(--muted); }

.bars{ display:flex; flex-direction:column; gap:.55rem; margin-top:.6rem; }
.bar-row{ display:grid; grid-template-columns:minmax(10rem,16rem) 1fr 2.5rem;
  align-items:center; gap:.7rem; font-size:.82rem; }
.bar-label{ color:var(--ink); }
.bar-track{ height:.7rem; background:var(--rule-soft); border-radius:999px; overflow:hidden; }
.bar-fill{ display:block; height:100%; background:var(--blue); border-radius:999px; }
.bar-val{ font-family:var(--mono); font-weight:700; color:var(--blue-2); text-align:right; }

table.survey-items{ width:100%; border-collapse:collapse; margin-top:.6rem; font-size:.84rem; }
table.survey-items th, table.survey-items td{ text-align:left; padding:.4rem .5rem;
  border-bottom:1px solid var(--rule-soft); vertical-align:top; }
table.survey-items th{ font-size:.72rem; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); }
table.survey-items .num{ text-align:right; font-family:var(--mono); white-space:nowrap; }
table.survey-items .sec-row td{ font-weight:700; color:var(--head); background:var(--paper);
  padding-top:.6rem; border-bottom:1px solid var(--rule); }

.comment{ padding:.7rem 0; border-top:1px solid var(--rule-soft); }
.comment:first-of-type{ border-top:0; }
.comment-h{ font-size:.85rem; color:var(--ink); margin-bottom:.3rem; }
.comment-ts{ float:right; font-family:var(--mono); font-size:.72rem; }
.comment-q{ font-size:.76rem; color:var(--muted); margin:.4rem 0 .1rem; }
.comment-a{ font-size:.88rem; color:var(--ink); margin:0; white-space:pre-wrap; }

@media (max-width:560px){
  .bar-row{ grid-template-columns:1fr 2.5rem; }
  .bar-label{ grid-column:1 / -1; }
}
