/* =====================================================
   main.css
   PURPOSE: Global layout and shared styles that apply
   across the ENTIRE app. Every screen inherits these.

   ACRONYMS (ACR = Acronym) USED IN THIS FILE:
     - CSS  = Cascading Style Sheets, controls visuals
     - HTML = HyperText Markup Language, page structure
     - JS   = JavaScript, the programming language that
              makes the app interactive
     - px   = Pixels, a unit of screen measurement
     - vh   = Viewport Height, 1vh = 1% of screen height
     - z    = Z-axis, the depth layer controlling which
              elements appear on top of others

   IMPORTANT RULES:
     - NO colors are hardcoded (hardcoded = written as
       a fixed value directly instead of using a
       variable) here. All colors use variables from
       theme.css (e.g. var(--color-background))
     - Screen-specific styles belong in their OWN file
       (e.g. home.css, deck.css, card-editor.css)
     - This file should rarely need editing
   ===================================================== */


/* ── RESET ────────────────────────────────────────────────
   Removes default browser (Chrome, Firefox, Safari)
   spacing and sizing inconsistencies so our styles
   are consistent everywhere.
   * selector = targets EVERY element on the page.
   ::before and ::after = pseudo-elements (pseudo =
   fake elements created by CSS that don't exist in
   the HTML but can be styled) that some elements use
   for decorative content.                           */
*,
*::before,
*::after {
  box-sizing: border-box;
  /* box-sizing: border-box = padding and borders are
     included INSIDE the element's width and height
     rather than added on top. This prevents elements
     from being wider than expected. */
  margin:     0;
  padding:    0;
}


/* ── ROOT APP LAYOUT ──────────────────────────────────────
   html and body must both have height: 100% to pass
   full height down to child elements.

   #app-header and #bottom-nav are BOTH position: fixed —
   translucent bars that overlay on top of the screen so
   scrolled content passes underneath them and shows
   through their blur (the whole point of the iOS-style
   translucent-bar look). Being position: fixed removes
   them from body's normal flex flow entirely, which
   leaves #screen-container (flex: 1) as body's only real
   flex item — it fills the ENTIRE body height, running
   underneath both bars:

     ┌──────────────────┐
     │   #app-header    │  ← fixed, overlays on top
     ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
     │                  │
     │ #screen-container│  ← flex: 1, fills ALL of body,
     │  (flex: 1, the   │     including underneath both
     │  only real flex  │     fixed bars
     │  item in body)   │
     │                  │
     ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
     │   #bottom-nav    │  ← fixed, overlays on top
     └──────────────────┘

   Since #screen-container's own padding-top/padding-bottom
   reserve exactly --app-header-height and
   --bottom-nav-height of space (below), its actual CONTENT
   still starts and ends in the right place — only the
   scrollable BACKGROUND runs the full height, which is
   what lets it peek through the bars' blur while scrolling.
   Study mode manages this same clearance itself since it
   overrides this padding to 0 (see study.css).         */
html {
  height:     100%;
  width:      100%;
  overflow:   hidden;
  /* WHY THIS IS HERE (not just on body, below):
     When the root <html> element's own overflow is the
     default `visible`, the browser propagates <body>'s
     overflow value UP to the viewport instead of using it
     to clip body's own box — a long-standing CSS quirk
     (the UA stylesheet's "root/body overflow propagation"
     rule). That's harmless at real mobile widths, where
     body already fills the whole viewport edge to edge —
     "clip the viewport" and "clip body's own box" are the
     same rectangle either way. It stops being harmless the
     moment body is narrower than the viewport (the desktop
     adaptive layout below, or the phone frame this replaced)
     — with nothing clipping body's OWN box locally, anything
     positioned via router.js's screen-slide transition (the
     outgoing clone, and the incoming #screen-container while
     it's still animating in) painted straight through into
     the gray margin outside body instead of being cut off at
     its edge, briefly showing the previous/next screen's
     content out there mid-swipe. Giving html its own
     non-visible overflow here stops the propagation — body's
     own overflow: hidden (below) then actually applies to
     body's own box as a real local clip, same as any other
     element, and the leak is gone. */
}

/* ── BLUE LIGHT SENSITIVITY MODE ──────────────────────────
   Appearance setting (Profile → theme-manager.js's
   applyBlueLightIntensity()) — an adjustable warm-shift filter
   over the ENTIRE app, same idea as macOS Night Shift / f.lux /
   Android Night Light. See getStoredBlueLightIntensity()'s own
   jsdoc in theme-manager.js for the honest, non-oversold
   framing of what this does and doesn't do scientifically —
   short version: genuinely helps evening circadian disruption
   and general brightness/glare sensitivity, NOT a proven
   digital-eye-strain or eye-damage fix.

   Applied to <html> (:root) rather than #screen-container or
   any element further in, specifically so it composites the
   WHOLE app as one layer, including the fixed header and
   bottom nav — applying a filter to a smaller, SCROLLING
   element would risk the exact position: fixed containing-
   block bug router.js's own comments describe at length for
   `transform` (filter has the identical side effect: any
   element with a non-none filter becomes the containing block
   for its position: fixed descendants). <html> is safe here
   specifically because it's explicitly sized to fill the
   viewport exactly (height/width: 100% above, no page-level
   scroll — body has overflow: hidden below) so it never shifts
   what "fixed" is measured against, unlike a scrolling child
   would.

   --blue-light-intensity (0-100, set inline on <html> by
   applyBlueLightIntensity() — 0 whenever the attribute below
   isn't even present) scales every filter function linearly
   from neutral at 0 up to these hand-picked values at 100:
   sepia + a negative hue-rotate mix in a warm AMBER tone
   (plain sepia alone reads as muddy brown), while saturate and
   brightness pull back slightly since a warm shift alone can
   look oversaturated/too bright by comparison. Only applied at
   all while intensity > 0 (data-blue-light attribute) so it
   costs nothing when off. */
:root[data-blue-light="true"] {
  filter:
    sepia(calc(var(--blue-light-intensity) * 0.35%))
    saturate(calc(100% - var(--blue-light-intensity) * 0.1%))
    brightness(calc(100% - var(--blue-light-intensity) * 0.03%))
    hue-rotate(calc(var(--blue-light-intensity) * -0.06deg));
}

body {
  height:          100%;
  width:           100%;
  display:         flex;
  flex-direction:  column;
  /* flex-direction: column = header, screen container,
     and nav bar stack vertically on top of each other */
  overflow:        hidden;
  /* overflow: hidden = prevents the whole page from
     scrolling. Individual sections scroll instead. */
  font-family:     var(--font-primary);
  /* --font-primary = 'Segoe UI', sans-serif */
  font-size:       var(--font-size-body);
  /* --font-size-body = 16px */
  background-color: var(--color-background);
  /* --color-background = #0a0e2a dark blue */
  color:           var(--color-text-primary);
  /* --color-text-primary = #ffffff white */
  position:        relative;
  /* position: relative here is harmless on real phones —
     it only matters combined with the transform added
     below at desktop widths. */
}


/* ── DESKTOP ADAPTIVE LAYOUT ───────────────────────────────
   Below this breakpoint (real phones, and narrow browser
   windows) the app behaves exactly as before — full
   screen, edge to edge. Above it, the SAME single-column
   layout every screen already has just gets more breathing
   room — a wider centered content column instead of either
   (a) stretching that single mobile column edge-to-edge
   across a whole monitor, or (b) the fixed-size 430x844
   fake "phone in a box" mockup this used to be (dropped —
   it looked like a toy inside a real desktop shell, most
   noticeably once wrapped in Capacitor: on a wide-viewport
   Capacitor WebView, e.g. a tablet, THIS is what real users
   would have seen too, not a debug-only view). This is
   deliberately a light-touch adaptation, not a redesign —
   no screen's own markup/CSS changes, only how much width
   the shared shell gives it.

   HOW THE FIXED ELEMENTS (bottom nav, modals, the OCR
   overlay) STAY INSIDE THE COLUMN:
   body already has overflow: hidden (above). Adding
   transform here — translateZ(0) is a visual no-op — makes
   body establish a new CSS "containing block" for every
   position: fixed descendant in the app, no matter how
   deep in the HTML it lives. That means #bottom-nav, every
   .modal-backdrop, .shuffle-overlay, and
   .highlight-select-overlay all anchor to the COLUMN's own
   edges instead of the real browser viewport. This is a
   standard CSS technique — no JavaScript involved, and
   unchanged from before; only the column's own size/shape
   changed, not this mechanism.

   DEV LAYOUT OVERRIDE (js/utils/dev-layout.js):
   This breakpoint is automatic — it just reads the real
   window width. `html[data-layout="mobile"|"desktop"]`
   below lets a developer force either layout regardless of
   the ACTUAL window width, so both can be tested/fixed
   without physically resizing the browser every time. Not
   a beta-facing setting — no UI renders it; it's driven
   from the console (or by Claude, on request) via
   window.remsymSetLayout('mobile' | 'desktop' | null).
   Both override rulesets below live OUTSIDE this media
   query so they win at ANY width — an attribute selector
   (0,1,1 / 0,1,2) simply outranks the plain element
   selectors this media query uses (0,0,1 / 0,0,1), so no
   !important is needed either direction. */
@media (min-width: 481px) {
  html {
    display:          flex;
    align-items:      stretch;
    justify-content:  center;
    background-color: var(--ios-systemGray5);
  }

  body {
    width:         100%;
    max-width:     600px;
    /* 600px, not a bigger number: this is a light-touch
       adaptation of a single-column mobile layout, not a
       reflowed desktop redesign — much wider than this and
       every list row/card would look sparse and stretched
       rather than merely "roomier." */
    height:        100%;
    box-shadow:    0 0 24px rgba(0, 0, 0, 0.12);
    /* A soft ambient edge so the column still reads as
       its own surface against the page background, without
       the old shadow's "device floating in space" drama. */
    transform:     translateZ(0);
    /* translateZ(0) is a visual no-op — see comment above
       for why it's here. */
  }
}

/* Forces the adaptive column above even on a narrow
   window — the mirror image of the media query above,
   just not gated by actual width. */
html[data-layout="desktop"] {
  display:          flex;
  align-items:      stretch;
  justify-content:  center;
  background-color: var(--ios-systemGray5);
}

html[data-layout="desktop"] body {
  width:         100%;
  max-width:     600px;
  height:        100%;
  box-shadow:    0 0 24px rgba(0, 0, 0, 0.12);
  transform:     translateZ(0);
}

/* Forces plain full-bleed mobile layout even on a wide
   window — undoes every property the media query above
   would otherwise apply, restoring the same values the
   base html{}/body{} rules already use below 481px. */
html[data-layout="mobile"] {
  display:          block;
  background-color: transparent;
}

html[data-layout="mobile"] body {
  width:         100%;
  height:        100%;
  max-width:     none;
  max-height:    none;
  border-radius: 0;
  box-shadow:    none;
  transform:     none;
}


/* ── APP HEADER ───────────────────────────────────────────
   The bar at the very top showing the app name, the
   current screen subtitle (subtitle = the smaller text
   below the app name that changes per screen, controlled
   by setAppSubtitle() in ui-helpers.js), and the beta
   feedback button (far right — see #btn-report-feedback
   below).

   flex-shrink: 0 = header never shrinks or gets
   pushed off screen when content is tall.          */
#app-header {
  display:          flex;
  flex-direction:   row;
  /* row = title/subtitle stack on the left, feedback
     button pinned to the far right */
  justify-content:  space-between;
  align-items:      center;
  /* align-items: center on the ROW axis vertically
     centers both the title block and the button within
     the header's fixed height. */
  height:           calc(var(--app-header-height) + var(--safe-area-top));
  padding:          0 16px;
  padding-top:      var(--safe-area-top);
  box-sizing:       border-box;
  /* A fixed height (rather than sizing to content) means
     the title/subtitle stack just centers within it via
     the flex properties above — no fragile assumptions
     about exact text metrics. */

  /* iOS nav bars are translucent — a blurred, semi-see-
     -through background instead of a solid fill. */
  background-color: color-mix(in srgb, var(--color-nav-bg) 82%, transparent);
  backdrop-filter:      blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom:    var(--border-width) solid var(--color-border);
  /* --border-width = 1px hairline, --color-border = iOS
     separator color — replaces the old 2px colored border */

  position:         fixed;
  /* fixed (not sticky) so scrolled content passes BEHIND
     the header, the same way it does under #bottom-nav —
     that's what makes the blur/translucency actually show
     card colors coming through as the deck list scrolls,
     instead of just sitting flush above plain background.
     #screen-container's padding-top (below) reserves the
     matching space so content doesn't start out hidden
     underneath it. */
  top:              0;
  left:             0;
  width:            100%;
  z-index:          100;
  /* z-index: 100 = header sits above all screen content
     (z-index = controls which element appears on top
     when elements overlap) */
}

/* Wraps #app-title + #app-subtitle. Used to hold the
   "stack the title above the subtitle, left-aligned,
   centered vertically" behavior that used to live on
   #app-header itself, back when the header had nothing
   else in it — #app-header is a row now (title block +
   feedback button), so that stacking moved down one
   level onto this wrapper instead. min-width: 0 lets the
   title/subtitle truncate instead of pushing the
   feedback button off the right edge on a very narrow
   screen. */
#app-header-titles {
  display:         flex;
  flex-direction:  column;
  justify-content: center;
  align-items:     flex-start;
  min-width:       0;
}

#app-title {
  font-size:      24px;
  /* Deliberately a bit larger than .section-title (22px,
     e.g. "My Decks") so the app's own name reads as the
     more prominent heading on screen, not a token from
     the shared type scale — nothing between 22px and the
     next step (28px) fit "slightly bigger" well. */
  color:          var(--color-text-primary);
  /* Plain label color, not the accent — iOS reserves
     tint color for interactive elements, not headings. */
  font-weight:    600;
  letter-spacing: normal;
  margin:         0;
}

/* The subtitle changes per screen via JS (JavaScript).
   Examples: "Your Card Decks", "Study Mode", etc.  */
#app-subtitle {
  font-size:  var(--font-size-caption);
  color:      var(--color-text-secondary);
  margin-top: 1px;
}

/* Beta "Report a Bug / Feedback" button — far right of
   the header, out of the way but always visible. Same
   circular-fill-button shape as .modal__close (modal.css)
   for visual consistency with the rest of the app's
   small icon buttons. Icon markup is injected by
   initFeedbackButton() (js/features/feedback.js), not
   hardcoded in index.html. */
.header-icon-btn {
  display:          flex;
  align-items:      center;
  justify-content:  center;
  flex-shrink:      0;
  width:            32px;
  height:           32px;
  background-color: var(--ios-systemFill);
  border:           none;
  border-radius:    999px;
  color:            var(--color-text-secondary);
  cursor:           pointer;
  padding:          0;
  transition:       background-color 0.2s ease, color 0.2s ease,
                    transform 0.15s ease;
}

.header-icon-btn:hover {
  background-color: var(--ios-secondarySystemFill);
  color:            var(--color-text-primary);
}

.header-icon-btn:active {
  transform: scale(0.92);
}

/* The feedback button's icon uses the app's accent color
   instead of .header-icon-btn's default secondary-gray —
   same var()/convention as .deck-search-toggle (home.css)
   — so it reads as an inviting action, not blend-in
   chrome. Color stays green through hover/active too
   (only the background tints), matching how
   .deck-search-toggle behaves. */
#btn-report-feedback {
  color: var(--color-accent-amber);
}

#btn-report-feedback:hover {
  color: var(--color-accent-amber);
}


/* ── SCREEN CONTAINER ─────────────────────────────────────
   This is where all screens are injected by router.js
   (router.js = the file that handles all screen
   navigation and swaps content in here).

   flex: 1 = this container takes ALL remaining vertical
   space between the header above and the nav bar below.
   This replaces the old position: absolute approach
   which used hardcoded pixel offsets (top: 56px,
   bottom: 64px) that broke when screen sizes changed.

   min-height: 0 = CRITICAL for flex children.
   Without this the browser refuses to let the container
   shrink below its natural content size, which causes
   content to push outside the screen boundaries.

   overflow-y: auto = the screen content scrolls
   vertically inside this container if it is taller
   than the available space. The header and nav bar
   stay fixed in place.                             */
#screen-container {
  flex:       1;
  min-height: 0;
  /* min-height: 0 = allows flex child to shrink
     correctly. Required for flex: 1 to work as
     expected in all browsers. */
  overflow-y: auto;
  overflow-x: hidden;
  position:   relative;
  /* position: relative = allows absolutely positioned
     (absolute = placed at exact X/Y coordinates
     relative to this container) elements inside
     screens to work correctly */
  padding:        16px;
  padding-top:    calc(16px + var(--app-header-height) + var(--safe-area-top));
  padding-bottom: calc(16px + var(--bottom-nav-height) + var(--safe-area-bottom));
  /* #app-header and #bottom-nav are both position: fixed,
     which removes them from body's flex layout entirely —
     without this, #screen-container's content would start
     out hidden underneath the header and, at the bottom,
     end up permanently hidden underneath the nav bar with
     no way to scroll past it (both bars just overlay on
     top of the container's full-height scrolling area).
     This padding reserves exactly that much space on each
     side so content starts below the header and scrolling
     all the way down clears the fixed nav bar.
     Note: study mode overrides this padding to 0
     because it manages its own internal spacing. */
}

/* ── SCREEN TRANSITION (iOS-style push/pop) ───────────────
   .screen-transition-clone marks the throwaway deep clone
   of #screen-container that router.js creates for the
   outgoing screen during every navigateTo()/goBack() call,
   then slides past the real (incoming) #screen-container
   before removing it — see renderWithTransition() in
   router.js for the full mechanics. It's purely a marker
   class for identification here (all its actual styling —
   position, size, overflow, transform, z-index — is set
   inline by router.js instead, since #screen-container's
   own id-selector rules elsewhere in this file would
   otherwise win on specificity and fight with a class-based
   override here). */


/* ── SHARED BUTTON BASE STYLE ─────────────────────────────
   All buttons in the app inherit from this base class.
   Individual button variants below override specific
   properties as needed.                            */
.btn {
  display:          inline-flex;
  /* inline-flex = button sizes to its content but
     uses flex internally to align icon and text */
  align-items:      center;
  justify-content:  center;
  gap:              6px;
  /* gap = space between icon and text inside button */
  padding:          10px 18px;
  border:           none;
  border-radius:    var(--border-radius);
  /* --border-radius = 12px, iOS-style rounded corners */
  background-color: var(--color-button-bg);
  /* --color-button-bg = iOS system blue */
  color:            var(--color-button-text);
  /* --color-button-text = white */
  font-size:        var(--font-size-body);
  font-weight:      600;
  font-family:      var(--font-primary);
  cursor:           pointer;
  /* cursor: pointer = shows the hand icon so users
     know the element is clickable */
  transition:       background-color 0.15s ease,
                    opacity          0.15s ease,
                    transform        0.15s cubic-bezier(0.34, 1.56, 0.64, 1);
  /* the cubic-bezier here overshoots slightly on the
     way back to scale(1), giving buttons a light
     spring-like "bounce" on release, closer to iOS
     tactile feedback than a plain linear ease. */
  user-select:      none;
  /* user-select: none = prevents text inside buttons
     from being highlighted when clicking quickly */
}

.btn:hover {
  background-color: var(--color-button-hover);
}

.btn:active {
  transform: scale(0.96);
  opacity:   0.85;
  /* iOS buttons dim slightly and shrink a touch on
     press — a satisfying tactile (tactile = giving a
     physical-feeling response) click effect */
}


/* ── BUTTON VARIANTS ──────────────────────────────────────
   These classes are added alongside .btn to override
   specific properties for different button types.  */

/* Danger button — used for delete actions.
   iOS destructive actions are usually plain red text,
   not a filled red button, so this matches that. */
.btn--danger {
  background-color: transparent;
  color:            var(--ios-systemRed);
}

.btn--danger:hover {
  background-color: color-mix(in srgb, var(--ios-systemRed) 12%, transparent);
}

/* Back / plain button — transparent, tint-colored text,
   no border. Matches iOS's plain nav-bar button style. */
.btn--back {
  background-color: transparent;
  color:            var(--color-accent-amber);
  /* --color-accent-amber now resolves to systemBlue */
  padding:          6px 10px;
  font-weight:      400;
}

.btn--back:hover {
  background-color: var(--tint-accent-soft);
}

/* Save button — same filled-blue treatment as the
   default .btn now that amber has been retired as an
   accent, kept as its own class for call sites that
   want to be explicit about intent. */
.btn--save {
  background-color: var(--color-accent-amber);
  color:            var(--color-button-text);
  font-weight:      600;
}

/* Shuffle button — a secondary action wherever it
   appears (currently Deck View's stats bar; Study Mode's
   header icon button has its own styling in study.css),
   so it gets iOS's "tinted" treatment — neutral fill,
   accent-colored text/icon — rather than a solid fill. */
.btn--shuffle {
  background-color: var(--ios-tertiarySystemFill);
  color:             var(--color-accent-amber);
  font-size:         var(--font-size-footnote);
  font-weight:       600;
  padding:           6px 12px;
}

.btn--shuffle:hover {
  background-color: var(--ios-secondarySystemFill);
  color:             var(--color-accent-amber);
}


/* ── SECTION TITLE ────────────────────────────────────────
   Used for headings like "Your Card Decks". iOS large-
   title style: plain bold text, no accent border bar.  */
.section-title {
  font-size:     var(--font-size-title2);
  color:         var(--color-text-primary);
  margin-bottom: var(--space-4);
  font-weight:   700;
  border-left:   none;
  padding-left:  0;
}


/* ── EMPTY STATE MESSAGE ──────────────────────────────────
   Shown when a list has no items yet, for example
   "No decks yet. Tap the + button to create one!"  */
.empty-state {
  text-align:  center;
  color:       var(--color-text-secondary);
  padding:     40px 16px;
  font-size:   var(--font-size-body);
  line-height: 1.6;
}


/* ── ERROR MESSAGE ────────────────────────────────────────
   Shown when something goes wrong in the app.      */
.error {
  color:      var(--ios-systemRed);
  text-align: center;
  padding:    20px;
}


/* ── HIDDEN UTILITY CLASS ─────────────────────────────────
   Add class="hidden" to any element to hide it.
   !important = this rule overrides all other display
   rules no matter what other styles are applied.   */
.hidden {
  display: none !important;
}


/* ── CUSTOM SCROLLBAR ─────────────────────────────────────
   Styles the scrollbar to match the dark theme.
   ::-webkit-scrollbar = only works in Chrome, Edge,
   and Safari (webkit = the browser engine used by
   those browsers). Firefox uses a different approach. */
::-webkit-scrollbar {
  width: 6px;
  /* 6px = thin scrollbar so it is not intrusive */
}

::-webkit-scrollbar-track {
  background: var(--color-background);
  /* Track (track = the full scrollbar background rail)
     matches the dark blue app background */
}

::-webkit-scrollbar-thumb {
  background:    var(--ios-systemGray3);
  /* Thumb (thumb = the draggable scrollbar handle) —
     iOS doesn't tint scrollbars with the accent color,
     it uses a neutral gray. */
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--ios-systemGray2);
}


/* ── PLACEHOLDER SCREEN STYLES ────────────────────────────
   PURPOSE: Styles for the Game Modes and Profile
   screens that are not yet built. These give the
   placeholder screens a clean look that matches the
   rest of the app.

   ⚠️ When you build out these screens for real,
   remove these styles and add screen-specific CSS
   files instead (e.g. styles/game-modes.css).     */

.placeholder-screen {
  display:         flex;
  flex-direction:  column;
  align-items:     center;
  justify-content: center;
  text-align:      center;
  padding:         60px 24px;
  gap:             16px;
}

/* Large icon at the top of placeholder screens */
.placeholder-screen__icon {
  font-size:   64px;
  line-height: 1;
}

/* Heading on placeholder screens */
.placeholder-screen h3 {
  font-size:   var(--font-size-title3);
  color:       var(--color-text-primary);
  font-weight: 700;
}

/* Description text on placeholder screens */
.placeholder-screen p {
  font-size:   var(--font-size-body);
  color:       var(--color-text-secondary);
  max-width:   280px;
  line-height: 1.6;
}


/* ── SETTINGS GROUP / ROW ─────────────────────────────────
   iOS "grouped list" style card, used for settings rows
   like the Appearance toggle on the Profile screen.    */
.settings-group {
  background-color: var(--color-card-bg);
  border-radius:     var(--radius-lg);
  box-shadow:        var(--shadow-elevation-1);
  margin-bottom:      var(--space-5);
  overflow:           hidden;
}

.settings-row {
  display:          flex;
  align-items:      center;
  justify-content:  space-between;
  gap:              var(--space-3);
  padding:          var(--space-4);
  border-bottom:    var(--border-width) solid var(--color-border);
}

.settings-group .settings-row:last-child {
  border-bottom: none;
}

.settings-row__label {
  display:        flex;
  flex-direction: column;
  gap:            2px;
  flex:           1;
  min-width:      0;
  font-size:      var(--font-size-body);
  color:          var(--color-text-primary);
  font-weight:    500;
}

/* Optional second line under a settings row's label —
   e.g. the "Always White Flashcards" row explaining what
   it does. Plain single-line labels (like Appearance) just
   don't include this, no layout change either way. */
.settings-row__caption {
  font-size:   var(--font-size-footnote);
  color:       var(--color-text-secondary);
  font-weight: 400;
}


/* ── SETTINGS GROUP TITLE ──────────────────────────────────
   iOS grouped-list convention: a small uppercase caption
   above a .settings-group naming the section (e.g.
   "ACKNOWLEDGEMENTS"). Optional — most .settings-group
   blocks won't need one. */
.settings-group-title {
  font-size:      var(--font-size-footnote);
  color:          var(--color-text-secondary);
  font-weight:    600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin:         0 0 var(--space-2) var(--space-1);
}

/* A link inside a .settings-row__caption (e.g. crediting a
   license) — stays part of the row's card, never spills
   text outside the .settings-group surface. */
.settings-row__link {
  color:           var(--color-button-bg);
  font-weight:     600;
  text-decoration: none;
}

.settings-row__link:hover {
  text-decoration: underline;
}


/* ── SETTINGS TOGGLE (iOS-style switch) ───────────────────
   A real on/off switch for boolean settings rows (e.g.
   "Always White Flashcards" on Profile) — distinct from
   .segmented-control above, which is for picking one of
   several named options (System/Light/Dark), not a plain
   yes/no. Built from a checkbox input made invisible but
   still focusable/clickable over the whole track, so it
   stays keyboard/screen-reader accessible as a real
   checkbox rather than a div with a click handler. */
.settings-toggle {
  position:     relative;
  display:      inline-block;
  flex-shrink:  0;
  width:        51px;
  height:       31px;
}

.settings-toggle input {
  position: absolute;
  inset:    0;
  margin:   0;
  opacity:  0;
  cursor:   pointer;
}

.settings-toggle__track {
  position:         absolute;
  inset:            0;
  border-radius:    999px;
  background-color: var(--ios-systemGray4);
  transition:        background-color 0.2s ease;
  pointer-events:   none;
}

.settings-toggle__thumb {
  position:         absolute;
  top:              2px;
  left:             2px;
  width:            27px;
  height:           27px;
  border-radius:    50%;
  background-color: #fff;
  box-shadow:       0 2px 4px rgba(0, 0, 0, 0.25);
  transition:        transform 0.2s ease;
}

.settings-toggle input:checked + .settings-toggle__track {
  background-color: var(--ios-systemGreen);
  /* iOS switches turn systemGreen when on, regardless of
     the app's own accent color — matches the real OS
     control this is styled after. */
}

.settings-toggle input:checked + .settings-toggle__track .settings-toggle__thumb {
  transform: translateX(20px);
}

.settings-toggle input:focus-visible + .settings-toggle__track {
  outline:        2px solid var(--color-accent-amber);
  outline-offset: 2px;
}


/* ── SETTINGS SLIDER ROW (Blue Light Sensitivity) ─────────
   Stacks the label/caption ABOVE the control instead of
   .settings-row's usual side-by-side layout — a drag slider
   needs real horizontal room, unlike the compact toggle switch
   above, which fits fine inline next to its label. */
.settings-row--stacked {
  flex-direction: column;
  align-items:    stretch;
  gap:            var(--space-3);
}

.settings-row--stacked .settings-row__label {
  flex: none;
}

.settings-row__label-line {
  display:         flex;
  align-items:     center;
  justify-content: space-between;
  gap:             var(--space-3);
}

/* Live "N%" readout next to the label, updated as the thumb
   is dragged — see profile.js's slider 'input' handler.
   tabular-nums keeps the digit width constant (0 vs 100 are
   different widths in most fonts otherwise), so the label text
   next to it doesn't visibly shift as the number changes. */
.settings-row__value {
  font-variant-numeric: tabular-nums;
  color:                var(--color-text-secondary);
  font-weight:          600;
  flex-shrink:          0;
}

/* Reset to a blank canvas (appearance: none) so every part
   below is drawn by this app's own rules instead of the
   browser's native slider chrome, which looks wildly
   inconsistent across platforms. background is set inline by
   profile.js (a linear-gradient split at the current value) to
   show progress — a fill up to the thumb — that plain CSS alone
   can't express for a native <input type="range">. */
.settings-slider {
  -webkit-appearance: none;
  appearance:         none;
  width:               100%;
  height:              4px;
  border-radius:       999px;
  background-color:    var(--ios-systemGray4);
  cursor:              pointer;
}

.settings-slider::-webkit-slider-runnable-track {
  height:           4px;
  border-radius:    999px;
  /* Transparent — the colored track fill comes from the
     element's own inline `background` gradient (see above),
     not this pseudo-element, which just needs to exist so the
     thumb below has a track to sit on in WebKit/Blink. */
  background-color: transparent;
}

.settings-slider::-moz-range-track {
  height:           4px;
  border-radius:    999px;
  background-color: transparent;
}

/* Same thumb look as .settings-toggle__thumb above — a plain
   white circle with a soft drop shadow — for visual consistency
   between the two Appearance controls. */
.settings-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance:         none;
  width:               24px;
  height:              24px;
  margin-top:          -10px; /* Centers the 24px thumb over the 4px track */
  border:              none;
  border-radius:       50%;
  background-color:    #fff;
  box-shadow:          0 2px 4px rgba(0, 0, 0, 0.25);
}

.settings-slider::-moz-range-thumb {
  width:            24px;
  height:           24px;
  border:           none;
  border-radius:    50%;
  background-color: #fff;
  box-shadow:       0 2px 4px rgba(0, 0, 0, 0.25);
}

.settings-slider:focus-visible {
  outline: none;
}

.settings-slider:focus-visible::-webkit-slider-thumb {
  outline:        2px solid var(--color-accent-amber);
  outline-offset: 2px;
}

.settings-slider:focus-visible::-moz-range-thumb {
  outline:        2px solid var(--color-accent-amber);
  outline-offset: 2px;
}


/* ── SEGMENTED CONTROL ────────────────────────────────────
   Generic iOS segmented control — a compact toggle for a
   small set of mutually-exclusive options (e.g. the
   Appearance: System/Light/Dark control on Profile).   */
.segmented-control {
  display:          inline-flex;
  padding:          2px;
  gap:              2px;
  background-color: var(--ios-systemGray6);
  border-radius:    var(--radius-sm);
}

.segmented-control__option {
  padding:          6px 12px;
  background-color: transparent;
  border:           none;
  border-radius:    calc(var(--radius-sm) - 2px);
  color:            var(--color-text-secondary);
  font-size:        var(--font-size-footnote);
  font-weight:      600;
  font-family:      var(--font-primary);
  cursor:           pointer;
  transition:       background-color 0.2s ease, color 0.2s ease;
}

.segmented-control__option--active {
  background-color: var(--color-card-bg);
  color:             var(--color-text-primary);
  box-shadow:        var(--shadow-elevation-1);
}