/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/*
 * Material Symbols base rule.
 *
 * Icons are rendered as ligatures — <span class="material-symbols-outlined">rate_review</span>
 * — and the class that turns that word into a glyph lives only in Google's
 * remote stylesheet. On a cold cache the span is just the literal word in the
 * body font at full width, so the sidebar visibly rearranged itself while the
 * font was in flight: "rate_review" is 11 characters and shoved "Review Queue"
 * onto two lines, while shorter icon names shifted less. The distortion scaled
 * with the icon NAME, which is the fingerprint of this failure.
 *
 * Declaring the rule here (served from our own origin, already in the critical
 * path) reserves the glyph box before Google's CSS arrives, so nothing can move.
 *
 * display: inline-block is load-bearing, not decoration: a <span> is a
 * non-replaced inline element, and width/height/overflow are ignored on those.
 * Remove it and this whole rule silently stops working.
 */
.material-symbols-outlined {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  display: inline-block;
  width: 1em;       /* em, so the per-icon inline font-size in the views still applies */
  height: 1em;
  overflow: hidden; /* clip the ligature word until the font resolves it */
  /* An inline-block with overflow != visible takes its baseline from its bottom
     margin edge (CSS 2.1 §10.8.1) rather than its last line box, so the two
     lines above shift every icon in a baseline-aligned context. Today every
     text-adjacent icon sits in a flex container with items-center, where
     baseline is never consulted — this keeps the next non-flex caller working. */
  vertical-align: middle;
  font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
}

/*
 * Self-hosted UI faces — Archivo (interface) and IBM Plex Mono (every figure,
 * ID, receipt number, reference, phone and date).
 *
 * Self-hosted, not linked from Google, for the reason documented above: a
 * remote font arriving late is what rearranged the sidebar. That failure was
 * fixed for the icon font by reserving its box here; the fix for a TEXT face is
 * to serve it from our own origin so it is in the critical path from the start.
 * Adding a third Google Fonts link would have reintroduced the same class of
 * bug on every page.
 *
 * Archivo is a VARIABLE font: one file covers weights 400-700, which is why
 * there are two Archivo files and not eight. Only the latin and latin-ext
 * subsets are shipped; the UI is English and the Vietnamese subset is dead
 * weight. 124 KB total, against the 446 KB the icon font already costs.
 *
 * Propshaft rewrites these url() references to digested paths at build time.
 * app/assets/fonts is in the asset load path, so the bare filename is the
 * logical path.
 */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/archivo-400-700-latin-7a918f31.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/archivo-400-700-latin-ext-4e7e2dd1.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-400-latin-d13bb5b4.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-400-latin-ext-182606ec.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-500-latin-deab9c2b.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-500-latin-ext-2cd882f8.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-600-latin-0fdd541f.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-600-latin-ext-71edd651.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/*
 * Focus ring — ONE mechanism, and it wins deliberately.
 *
 * Two systems wanted to draw this. The design system specifies a :focus-visible
 * box-shadow; Tailwind's 174 `focus:ring-*` utilities across 30 view files also
 * write box-shadow, through --tw-ring-shadow. Left alone they fight, and which
 * one you see depends on whether the element happens to carry a ring utility.
 *
 * This file is loaded AFTER tailwind.css and these rules are UNLAYERED, and
 * unlayered declarations beat anything inside a cascade layer regardless of
 * specificity. So these win over Tailwind's utilities everywhere, and focus
 * looks the same on every control in the app from this commit onward.
 *
 * The leftover focus:ring-* utilities are now visually dead. They come out as
 * each view migrates rather than in one 33-file sweep — see
 * tasks/clearline-design-system.md.
 *
 * :focus-visible, not :focus — and it is worth being accurate about what that
 * actually does, because the earlier version of this comment was not.
 *
 * It does NOT mean keyboard-only. Browsers match :focus-visible on a
 * MOUSE-CLICKED text input, tel input, date input, select and textarea, because
 * those accept typing and the user needs to see where it will land. Measured in
 * Chrome against these exact forms. What it excludes is the click on a button or
 * a link, where a ring after the fact tells you nothing you did not just do.
 *
 * So: every field shows the ring however you reach it, and buttons show it only
 * on keyboard. That is the behaviour we want; the old comment described a
 * keyboard-only world that never existed and would have sent the next person
 * hunting for a bug that is not there.
 */
:focus-visible {
  outline: none;
  /*
   * The ring is COMPOSED with whatever elevation the element already has, not
   * written over it. A bare `box-shadow: var(--focus-ring)` replaces the whole
   * property, and Tailwind builds .shadow-card's elevation out of the five
   * --tw-* layers below. reports/index.html.erb:47 is a focusable link carrying
   * shadow-card: keyboard-tabbing to it made the card go flat, so the one
   * element you are looking at was the one that lost its depth.
   *
   * --tw-ring-shadow and --tw-ring-offset-shadow are deliberately left out. Our
   * ring replaces Tailwind's; drawing both would double it.
   *
   * The fallbacks matter. Tailwind only emits the @property registrations for
   * these when a shadow utility is used somewhere in the build. Without them a
   * bare var() would resolve to nothing and take the entire declaration with
   * it, leaving no focus ring at all.
   */
  box-shadow:
    var(--focus-ring),
    var(--tw-inset-shadow, 0 0 #0000),
    var(--tw-inset-ring-shadow, 0 0 #0000),
    var(--tw-shadow, 0 0 #0000);
}

/*
 * The focus BORDER, which the ring above does not cover.
 *
 * Migrating the forms deleted 16 `focus:border-blue-500` utilities on the
 * grounds that this stylesheet supersedes them. For the ring, it does. For the
 * border it does not: the rule above writes `outline` and `box-shadow` and never
 * touches `border-color`, so the fields quietly lost the colour change they had
 * on focus and kept only the ring.
 *
 * Restored here rather than per-view, so it is one rule instead of a utility on
 * every input, and it follows --focus-ring-color, which means it tracks the
 * accent and flips with the palette. Scoped to the controls that had it: a
 * blanket `:focus-visible { border-color }` would repaint the border of every
 * focusable card and table row that happens to have one.
 */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  border-color: var(--focus-ring-color);
}

/*
 * Windows High Contrast / forced-colors does not paint box-shadow at all, so
 * the rule above leaves a keyboard user there with no focus indicator whatever.
 * Hand the outline back in that mode only. `outline-offset` keeps it clear of
 * the control's own border, matching the ring's 2px gap.
 */
@media (forced-colors: active) {
  :focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

/*
 * Mouse focus: neutralise Tailwind's ring without disturbing anything else.
 *
 * Resetting --tw-ring-shadow rather than box-shadow is the careful part.
 * Tailwind composes box-shadow from five variables, so zeroing this one removes
 * only the ring; a card's resting --tw-shadow survives. `box-shadow: none` here
 * would have flattened any focused element that legitimately has elevation.
 */
:focus:not(:focus-visible) {
  --tw-ring-shadow: 0 0 #0000;
  /*
   * The OFFSET ring has to go too. Zeroing only --tw-ring-shadow deletes the
   * coloured ring and leaves the white ring that existed to offset it, so a
   * mouse click on the Save button in students/_form and courses/_form painted
   * a bare 2px white halo around a blue button. Both carry focus:ring-offset-2.
   */
  --tw-ring-offset-shadow: 0 0 #0000;
}
