/* The banner's right-hand controls — the theme switch and the kebab menu.
   ============================================================
   Loaded on every page by both systems: base.njk links it, and
   lib/legacy-chrome.mjs injects it beside keys.css. The markup is in
   _includes/partials/banner-tools.njk and, verbatim, in legacy-chrome's
   banner(); keep the three in step.

   Wherever the bar has room, which is 768px up rather than the 1280 this
   started at. The gate was the sidebar's breakpoint because that was the
   number to hand, not because the banner needed it: the message and the call
   to action are centered and these are pinned to the end, so what stands
   between them narrows by half a pixel for every pixel off the window. At 768
   that measures 26.6px of clear air between the button's drawn edge and the
   switch, and the two do not meet until 715.

   1280 meant every tablet in portrait — an iPad Pro has 1024 — fell back to
   the floating button, which is a 42px circle sitting on top of the page in
   the top right while a bar with 400px of empty purple in it ran along the
   top.

   Below 768 the switch moves into the nav drawer's wordmark row instead (see
   css/site-nav.css); the kebab does not follow it. Two theme controls on one
   screen is one too many, which is what the floating button's two hiding
   rules are for — this sheet's, at the widths the banner has it, and
   site-nav.css's below them.

   Everything here has to read against the banner's #23004D, which is darker
   than either theme's paper — so the colors are written out rather than
   taken from the theme tokens, and they do not change when the theme does.
   The switch's state is what changes. */

/* ---- the banner's call to action ----
   Outside the desktop-only block below: the link is on every screen. Its drawn
   edge is not — below 600px the sentence itself becomes the link and the box
   goes; see the phone section at the foot of this file.

   The same hand as the switch beside it, and the same font as the switch's
   label — but where that label is a caption on a control, this is the one
   thing on the bar anybody is meant to press. So it takes the weight and the
   contrast the label deliberately does not: 600 against 400, and 90% white
   against 62%. The character is in the line, not in the type.

   The edge is baked geometry rather than generated, for the reason the
   switch's frame is: one button at one size on every page has nothing for a
   per-element seed to vary. It is hand-ink's own output for a 128x36 box —
   which is that module's judgment of how much license a box this small can
   carry, and why it is a single pass rather than two (below 46px on the short
   side, two strokes a pixel apart read as one heavy one rather than as a line
   gone over twice). */
/* The question stays in the sans — a second mono line here would compete with
   the mono heading below it.

   It leads, though, and used to do the opposite. At 15px/400 against a button
   at 16px/600 in mono inside a drawn box, it lost on size, weight, color,
   face and enclosure at once — five axes, all to the button. That ordering is
   backward for what the bar is for: the question is the part that says who
   this is addressed to, and the button is the part everybody presses anyway.
   Students were reading the button, missing the question and signing up on a
   page meant for their instructor.
   18px, weight 500, undimmed. The button is untouched; this is the sentence
   catching up with its own answer. */
/* Selected through .gs-banner, and not as a bare .gs-ask, on purpose. The
   sentence is a <p>, and ten other sheets style it as one — src/css/site.css
   plus the nine byte-exact style-*.css extractions of the old embedded chrome,
   each carrying `.gs-banner p{font-size:16px;font-weight:300}`. That selector
   is a class and a type, so a bare `.gs-ask` loses to all ten no matter what
   order they load in. Two classes beats them outright, and the rule stops
   depending on this sheet coming last. Family and margin are restated for the
   same reason: whichever of the ten wins, none of it should reach this. */
.gs-banner .gs-ask {
  font-family: Roboto, sans-serif;
  font-weight: 500;
  font-size: 18px;
  letter-spacing: 0.01em;
  color: #ffffff;
  margin: 16px 0;
}
.gs-banner .gs-btn-box {
  position: relative;
  border: 0;
  border-radius: 0;
  /* the strokes overshoot the corners, so the box cannot clip its own edge */
  overflow: visible;
}
.gs-btn-ink {
  position: absolute;
  left: -4px;
  top: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  overflow: visible;
  pointer-events: none;
  fill: none;
}
.gs-btn-ink path {
  /* Off full white, and a hair thinner. At 1.6px of pure white it was the
     brightest thing on the screen and pulled against the heading below it;
     the button should be the first thing you find when you look for it, not
     the first thing you see. Hover puts both back. */
  stroke: rgba(255, 255, 255, 0.72);
  stroke-width: 1.4;
  stroke-linecap: round;
  /* the viewBox is stretched to whatever the words measure; without this the
     stroke stretches with it and the verticals come out heavier than the
     horizontals */
  vector-effect: non-scaling-stroke;
  transition: stroke-width 0.18s ease, stroke 0.18s ease;
}
.gs-banner .gs-btn-box a {
  position: relative;
  font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.9);
}
/* The box carries the affordance where there is room for a box, so the mark
   stays out of the way and the link is labeled by the short form. The phone
   block at the foot of this file swaps both. */
.gs-btn-chev { display: none; }
.gs-lbl-long { display: none; }
/* No fill on hover: a straight-edged rectangle behind a wobbled line shows its
   corners through. The line thickens instead, which is what a hand does. */
.gs-banner .gs-btn-box:hover { background: none; }
.gs-banner .gs-btn-box:hover .gs-btn-ink path {
  stroke: #ffffff;
  stroke-width: 2;
}
.gs-banner .gs-btn-box:hover a { color: #ffffff; }
.gs-banner .gs-btn-box a:focus-visible { outline: 2px solid #ffffff; outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .gs-btn-ink path { transition: none; }
}

/* ---- The bar on a phone ----
   Last in the file on purpose. Every rule below overrides one above it at the
   same specificity, so it wins by order; the alternative was bounding each
   desktop rule in a min-width block, which is a second breakpoint to keep in
   step with this one for no gain.

   On a desktop the bar is two things: the question, then the button beside it.
   Below 420px that wrapped to two rows and the bar grew to 76px — half again
   the height of every other piece of chrome, and the first thing a reader
   meets.

   One row here too, and the arithmetic decides how. At 390px the bar has 326px
   inside its padding and the question alone wants 231 of them. Keeping the
   question and a separate button on one row forces both to about 13px — small
   enough that the message read as a caption beside a 28px heading, and quiet
   enough that students pressed the button without registering who it was
   addressed to. Dropping the button instead leaves the whole sentence at 17px
   with room to spare, and there is then nothing else on the bar to press. So
   the sentence becomes the link, and the chevron carries the affordance the
   box used to. */
@media (max-width: 600px) {
  /* The one phone value. src/css/site.css and legacy-chrome's
     banner-metrics.css each used to declare 48px here as well, and the latter
     a 76px case below 420 for the row the bar no longer wraps to; this sheet
     loads after both, so those were being silently overridden rather than
     consulted. They are gone, and the desktop 64px still comes from whichever
     of those two the page loads. */
  :root { --banner-h: 54px; }
  .gs-banner {
    height: var(--banner-h);
    flex-wrap: nowrap;
    gap: 0;
    padding: 0 14px 0 54px;   /* 54px clears the hamburger, at 8px + 40px */
  }
  /* The standing text is the link's label now, so it does not also stand — and
     the short label goes with the box it was written for. Display:none rather
     than a visually-hidden class on either: both are in the markup on every
     page, and a screen reader offered "Want to use Sway with your students?
     Start here" as one link name would read the wrong thing twice. */
  .gs-ask { display: none; }
  .gs-lbl-short { display: none; }
  .gs-lbl-long { display: inline; }
  /* The link may shrink below its own text's width — min-width: 0 — but the
     text inside it does not wrap; if the sentence ever outgrows the bar it is
     the clamp below that has to give, not the line count. */
  .gs-banner .gs-btn-outer { flex: 0 1 auto; min-width: 0; padding-left: 0; }
  .gs-banner .gs-btn-ink { display: none; }
  .gs-banner .gs-btn-box a {
    /* The sans, not the mono: this is a sentence now, and it sits above a page
       whose headings are already mono. Sized to the window so it is as large
       as the bar can hold — 17px from 415px up, down to 13px at 320. */
    font-family: Roboto, sans-serif;
    font-size: clamp(13px, 4.1vw, 17px);
    font-weight: 500;
    letter-spacing: 0.01em;
    line-height: 22px;
    /* The box the finger gets, which the words alone do not give: at a 22px
       line and no padding the link measured 22px tall, under the 24px floor
       WCAG 2.5.8 sets and well under the 44px 2.5.5 asks for. 11px top and
       bottom makes it 44 inside a 54px bar. Nothing is drawn on it here — the
       ink is hidden on this width — so the padding is only a target. */
    padding: 11px 0;
    color: #ffffff;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }
  /* The box is 30px of padding and a border the message needs, and it carries
     weight no type size can answer — at 15px inside it, it still took the eye
     off an 18px sentence. The mark keeps the hand without the enclosure.
     Named gs-btn-chev, not gs-chev: that one is taken, by the sidebar's
     disclosure button, and it is absolutely positioned at -32px — which put
     this mark off the left of the bar while still measuring 12x15 to a query.
     flex: 0 0 auto or it collapses: it is a flex item in an inline-flex link,
     and an SVG's min-content width is zero, so it stays in the DOM, measures
     12px to a query, and occupies nothing. */
  .gs-btn-chev {
    display: block;
    flex: 0 0 auto;
    width: 0.62em;
    height: 1em;
    margin-left: 0.45em;
  }
}

.gs-tools { display: none; }
.gs-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (min-width: 768px) {
  /* The banner centers its message; these sit at the end of the bar rather
     than in the flow of it, so the message stays centered on the screen and
     not on what is left of it.
     Both rules wait for js/banner-tools.js to set data-gs-tools: without it
     the switch and the menu would render and do nothing, and the floating
     button they replace would already be hidden. An attribute rather than a
     class because the exported instructor reports assign <html>'s className
     outright when the theme changes — see the note in banner-tools.js. */
  html[data-gs-tools] .gs-tools {
    display: flex;
    align-items: center;
    gap: 4px;
    position: absolute;
    top: 50%;
    right: 18px;
    transform: translateY(-50%);
  }

  /* ---- the switch ----
     The walkthroughs' toggle, drawn: a wobbled frame with a dot in it. Off is
     light mode, on is dark, and the dot crosses when it flips. */
  .gs-switch {
    display: flex;
    align-items: center;
    gap: 0.5em;
    padding: 4px 6px;
    border: 0;
    border-radius: 6px;
    background: none;
    cursor: pointer;
    line-height: 0;
  }
  .gs-switch svg { display: block; overflow: visible; }

  /* What it is, not what it does — the reading a physical switch gets. Set in
     the mono the rest of the site labels in, and quiet enough to be a caption
     on the control rather than a second button beside it.

     Both words are in the markup and the theme class picks one, so the label
     is right in the first frame: the class is resolved in <head> (see
     lib/theme-bootstrap.mjs), long before js/banner-tools.js runs, and a
     label that flickered from "dark" to "light" on every load would be worse
     than none. */
  .gs-switch-label {
    font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
    font-size: 0.68rem;
    line-height: 1;
    letter-spacing: 0.1em;
    color: rgba(255, 255, 255, 0.55);
    transition: color 0.2s ease;
  }
  .gs-switch-label i { font-style: normal; }
  .gs-switch-label .gs-d,
  html.dark-mode .gs-switch-label .gs-l { display: none; }
  html.dark-mode .gs-switch-label .gs-d { display: inline; }
  .gs-switch:hover .gs-switch-label { color: rgba(255, 255, 255, 0.85); }
  .gs-switch-frame {
    fill: none;
    stroke: rgba(255, 255, 255, 0.62);
    stroke-width: 1.6;
    stroke-linecap: round;
    transition: stroke 0.25s ease;
  }
  .gs-switch-dot {
    fill: #ffffff;
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), fill 0.25s ease;
  }
  .gs-switch[aria-checked="true"] .gs-switch-frame { stroke: rgba(255, 255, 255, 0.92); }
  .gs-switch[aria-checked="true"] .gs-switch-dot {
    transform: translateX(18px);
    fill: #b9bcff;
  }
  .gs-switch:hover .gs-switch-frame { stroke: #ffffff; }

  /* ---- the kebab ---- */
  .gs-more { position: relative; }
  .gs-kebab {
    display: block;
    padding: 4px 8px;
    border: 0;
    border-radius: 6px;
    background: none;
    cursor: pointer;
    line-height: 0;
  }
  .gs-kebab svg { display: block; }
  .gs-kebab circle { fill: rgba(255, 255, 255, 0.62); transition: fill 0.2s ease; }
  .gs-kebab:hover circle,
  .gs-kebab[aria-expanded="true"] circle { fill: #ffffff; }

  .gs-switch:focus-visible,
  .gs-kebab:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 1px;
  }

  /* ---- the menu ----
     Hangs off the bar rather than sitting in it, so it takes the page's own
     paper rather than the banner's purple.

     Which means asking two page systems for the same color under two sets of
     names: the templated pages have --text-strong and --surface-raised, the
     legacy ones --text-color and --card-bg, and neither knows the other's.
     Hence the chains — the first name that resolves wins, and the literal at
     the end is for a page that carries neither. */
  .gs-more-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 1310;
    min-width: 13.5rem;
    margin: 0;
    padding: 0.3rem;
    list-style: none;
    background: var(--surface-raised, var(--card-bg, #ffffff));
    border: 1px solid var(--border-subtle, var(--border-color, #dedcd7));
    border-radius: 8px;
    box-shadow: 0 10px 28px -12px rgba(0, 0, 0, 0.45);
  }
  .gs-more-menu[hidden] { display: none; }
  /* Guide, peering over the edge of the panel. Decorative and aria-hidden —
     it is not a control and does not go anywhere; it is there for whoever
     opens the menu. */
  .gs-guide {
    position: absolute;
    /* At the far end of the panel, where there is nothing above it but empty
       bar: the controls are all at the other end, and a mortarboard through
       the switch frame reads as a rendering fault rather than as a joke.
       High enough, too, that the hat stays inside the banner rather than
       being cut by its bottom edge. */
    top: -25px;
    left: 14px;
    pointer-events: none;
  }
  .gs-more-menu button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.8rem;
    width: 100%;
    padding: 0.5rem 0.65rem;
    border: 0;
    border-radius: 5px;
    background: none;
    color: var(--text-strong, var(--text-color, #111118));
    font: inherit;
    font-size: 0.88rem;
    text-align: left;
    cursor: pointer;
  }
  /* A tint rather than a token: --button-hover-bg exists on the legacy pages
     and not the templated ones, and this reads on either paper.

     So does the ring, which is here because opening the menu moves focus to
     its first item and the browser's own ring is a blue that belongs to
     neither theme. Keyed to :focus rather than :focus-visible: focus arrives
     here programmatically, so after a mouse press on the kebab the item is
     focused and does not match :focus-visible — the rule was written that way
     first and never applied. */
  .gs-more-menu button:hover,
  .gs-more-menu button:focus { background: rgba(128, 128, 160, 0.18); }
  .gs-more-menu button:focus {
    outline: 2px solid #7a7ae0;
    outline-offset: -2px;
  }
  .gs-more-menu kbd {
    font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
    font-size: 0.74em;
    padding: 0.1em 0.42em;
    border: 1px solid currentColor;
    border-radius: 3px;
    opacity: 0.7;
  }

  /* The floating button this replaces. Hidden rather than dropped: the page's
     own theme handler is bound to it, and the switch above presses it — a
     display:none button still fires its handler when clicked in script. */
  html[data-gs-tools] .theme-toggle { display: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .gs-switch-frame,
  .gs-switch-dot,
  .gs-switch-label,
  .sn-switch-frame,
  .sn-switch-dot,
  .sn-switch-label { transition: none; }
}
